source: trunk/src/sh_dbIO.c @ 481

Last change on this file since 481 was 481, checked in by katerina, 6 years ago

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

File size: 40.7 KB
Line 
1/* SAMHAIN file system integrity testing                                   */
2/* Copyright (C) 2015 Rainer Wichmann                                      */
3/*                                                                         */
4/*  This program is free software; you can redistribute it                 */
5/*  and/or modify                                                          */
6/*  it under the terms of the GNU General Public License as                */
7/*  published by                                                           */
8/*  the Free Software Foundation; either version 2 of the License, or      */
9/*  (at your option) any later version.                                    */
10/*                                                                         */
11/*  This program is distributed in the hope that it will be useful,        */
12/*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */
13/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
14/*  GNU General Public License for more details.                           */
15/*                                                                         */
16/*  You should have received a copy of the GNU General Public License      */
17/*  along with this program; if not, write to the Free Software            */
18/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
19
20#include "config_xor.h"
21
22#include <stdio.h>
23#include <string.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <unistd.h>
27
28#include "samhain.h"
29#include "sh_utils.h"
30#include "sh_dbIO_int.h"
31#include "sh_hash.h"
32#include "sh_dbIO.h"
33#include "sh_gpg.h"
34#include "sh_tiger.h"
35#include "sh_xfer.h"
36#include "sh_pthread.h"
37#include "sh_socket.h"
38#include "sh_files.h"
39
40#undef  FIL__
41#define FIL__  _("sh_dbIO.c")
42
43#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
44
45/* external prototypes                                                     */
46
47extern int get_the_fd (SL_TICKET ticket);
48
49SH_MUTEX_EXTERN(mutex_hash);
50
51/******************************************************************
52 *
53 * Get a single line
54 *
55 ******************************************************************/
56static FILE * sh_fin_fd = NULL;
57
58int sh_dbIO_getline (FILE * fd, char * line, const size_t sizeofline)
59{
60  size_t  n = 0;
61
62  SL_REQUIRE(sizeofline >= SH_MINIBUF, _("sizeofline >= SH_MINIBUF"));
63
64  if (NULL != fgets(line, sizeofline, fd))
65    {
66      n = strlen(line);
67      if (n > 0 && line[n-1] == '\n') {
68        n--; line[n] = '\0';
69      }
70    } 
71  else {
72    line[0] = '\0';
73    return -1;
74  }
75
76  return n;
77}
78
79/******************************************************************
80 *
81 * Fast forward to start of data
82 *
83 ******************************************************************/
84
85static void reopen_fin_fd(SL_TICKET fd)
86{
87  if (sh_fin_fd != NULL)
88    {
89      sl_fclose (FIL__, __LINE__, sh_fin_fd);
90      sh_fin_fd = NULL;
91    }
92
93  sh_fin_fd = fdopen(dup(get_the_fd(fd)), "rb");
94  return;
95}
96
97
98static int seek_sof(FILE * fd, char * line, int size, const char * file)
99{
100  long i;
101
102  while (1) 
103    {
104      i =  sh_dbIO_getline (fd, line, size);
105      if (i < 0 ) 
106        {
107          SH_FREE(line);
108          dlog(1, FIL__, __LINE__, 
109               _("The file signature database: %s does not\ncontain any data, or the start-of-file marker is missing (unlikely,\nunless modified by hand).\n"),
110               (NULL == file) ? _("(null)") : file);
111               
112          sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
113                           ( (NULL == file) ? _("(null)") : file)
114                           );
115          return -1;
116        }
117
118#if defined(SH_STEALTH)
119      if (0 == sl_strncmp (line, N_("[SOF]"), 5)) 
120#else
121      if (0 == sl_strncmp (line, _("[SOF]"),  5)) 
122#endif
123        break;
124    }
125  fflush(fd);
126  return 0;
127}
128
129static int sh_dbIO_setdataent (SL_TICKET fd, char * line, int size, 
130                               const char * file)
131{
132  int retval;
133
134  SL_ENTER(_("sh_dbIO_setdataent"));
135
136  sl_rewind (fd);
137  reopen_fin_fd(fd);
138
139  if (!sh_fin_fd)
140    {
141      dlog(1, FIL__, __LINE__, 
142           _("The file signature database: %s is not readable.\n"),
143           (NULL == file) ? _("(null)") : file);
144      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_P_NODATA,
145                       ( (NULL == file) ? _("(null)") : file)
146                       );
147      SL_RETURN( -1, _("sh_dbIO_setdataent"));
148    }
149
150  retval = seek_sof(sh_fin_fd, line, size, file);
151  SL_RETURN( retval, _("sh_dbIO_setdataent"));
152}
153
154static int sh_dbIO_setdataent_old (SL_TICKET fd, char * line, int size, 
155                                   const char * file)
156{
157  FILE * fdp;
158
159  SL_ENTER(_("sh_dbIO_setdataent_old"));
160
161  sl_rewind (fd);
162  fdp = sl_stream(fd, "r+");
163  if (0 != seek_sof(fdp, line, size, file))
164    SL_RETURN( SL_EREAD, _("sh_dbIO_setdataent_old"));
165  if (0 != ftruncate(fileno(fdp), ftello(fdp)))
166    {
167      char ebuf[SH_ERRBUF_SIZE];
168      int errnum = errno;
169      sh_error_message(errnum, ebuf, sizeof(ebuf));
170      sh_error_handle ((-1), FIL__, __LINE__, errnum, MSG_E_SUBGEN,
171                       ebuf, _("sh_dbIO_setdataent_old") );
172      SL_RETURN( SL_EWRITE, _("sh_dbIO_setdataent_old"));
173    }
174  SL_RETURN( 0, _("sh_dbIO_setdataent_old"));
175}
176
177/******************************************************************
178 *
179 * IO helper functions
180 *
181 ******************************************************************/
182
183
184static UINT32 * swap_32 (UINT32 * iptr)
185{
186#ifdef WORDS_BIGENDIAN
187  unsigned char swap;
188  unsigned char * ii = (unsigned char *) iptr;
189  swap = ii[0]; ii[0] = ii[3]; ii[3] = swap;
190  swap = ii[1]; ii[1] = ii[2]; ii[2] = swap;
191  return iptr;
192#else
193  return iptr;
194#endif
195}
196
197static UINT64 *  swap_64 (UINT64 * iptr)
198{
199#ifdef WORDS_BIGENDIAN
200#ifdef UINT64_IS_32
201  swap_32 ((UINT32*) iptr);
202#else
203  unsigned char swap;
204  unsigned char * ii = (unsigned char *) iptr;
205  swap = ii[0]; ii[0] = ii[7]; ii[7] = swap;
206  swap = ii[1]; ii[1] = ii[6]; ii[6] = swap;
207  swap = ii[2]; ii[2] = ii[5]; ii[5] = swap;
208  swap = ii[3]; ii[3] = ii[4]; ii[4] = swap;
209#endif
210  return iptr;
211#else
212  return iptr;
213#endif
214}
215
216static unsigned short *  swap_short (unsigned short * iptr)
217{
218#ifdef WORDS_BIGENDIAN
219  if (sizeof(short) == 4)
220    swap_32 ((UINT32*) iptr);
221  else
222    {
223      /* alignment problem */
224      unsigned char swap;
225      static unsigned short ooop;
226      unsigned char * ii;
227      ooop = *iptr;
228      ii = (unsigned char *) &ooop;
229      swap = ii[0]; ii[0] = ii[1]; ii[1] = swap;
230      return &ooop;
231    }
232  return iptr;
233#else
234  return iptr;
235#endif
236}
237
238static void swap_data(sh_filestore_t * ft)
239{
240  swap_32(&(ft->mode));
241  swap_32(&(ft->linkmode));
242  swap_64(&(ft->dev));
243  swap_64(&(ft->rdev));
244  swap_32(&(ft->hardlinks));
245  swap_32(&(ft->ino));
246  swap_64(&(ft->size));
247  swap_64(&(ft->atime));
248  swap_64(&(ft->mtime));
249  swap_64(&(ft->ctime));
250  swap_32(&(ft->owner));
251  swap_32(&(ft->group));
252  swap_32(&(ft->checkflags));
253#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
254  swap_32(&(ft->attributes));
255#endif
256  ft->mark = *(swap_short(&(ft->mark)));
257  return;
258}
259
260#define QUOTE_CHAR '='
261
262char * unquote_string (const char * str, size_t len)
263{
264  int    i = 0, t1, t2;
265  char * tmp = NULL;
266  size_t l2, j, k = 0;
267
268  SL_ENTER(_("unquote_string"));
269
270  if (str != NULL)
271    {
272      l2  = len - 2;
273      tmp = SH_ALLOC(len + 1);
274
275      for (j = 0; j <= len; ++j)
276        {
277          if (str[j] != QUOTE_CHAR)
278            {
279              tmp[k] = str[j];
280            }
281          else if (str[j] == QUOTE_CHAR && j < l2)
282            {
283              t1 = sh_util_hexchar(str[j+1]);
284              t2 = sh_util_hexchar(str[j+2]);
285              if ((t1|t2) >= 0)
286                {
287                  i = 16 * t1 + t2;
288                  tmp[k] = i; 
289                  j += 2;
290                }
291              else
292                {
293                  tmp[k] = str[j];
294                }
295            }
296          else
297            tmp[k] = str[j];
298          ++k;
299        }
300    }
301  SL_RETURN(tmp, _("unquote_string"));
302}
303
304static char * int2hex (unsigned char i, char * i2h)
305{
306  static char hexchars[] = "0123456789ABCDEF";
307
308  i2h[0] = hexchars[(((i) & 0xF0) >> 4)]; /* high */
309  i2h[1] = hexchars[((i) & 0x0F)];        /* low  */
310
311  return i2h;
312}
313
314char * quote_string (const char * str, size_t len)
315{
316  char * tmp;
317  char * tmp2;
318  size_t l2, j, i = 0, k = 0;
319  char   i2h[2];
320
321  SL_ENTER(_("quote_string"));
322
323  if (str == NULL)
324    {
325      SL_RETURN(NULL, _("quote_string"));
326    }
327
328  for (j = 0; j < len; ++j)
329    if (str[j] == '\n' || str[j] == QUOTE_CHAR) ++i;
330
331  l2 = len + 1;
332  if (sl_ok_muls(3, i) && sl_ok_adds(l2, (3*i)))
333    {
334      tmp = SH_ALLOC(len + 1 + 3*i);
335    }
336  else
337    {
338      sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
339                      _("integer overflow"), 
340                      _("quote_string"));
341      SL_RETURN(NULL, _("quote_string"));
342    }
343
344  for (j = 0; j <= len; ++j)
345    {
346      if (str[j] == '\n')
347        {
348          tmp2 = int2hex((unsigned char) '\n', i2h);
349          tmp[k] = QUOTE_CHAR; ++k;
350          tmp[k] = tmp2[0];    ++k;
351          tmp[k] = tmp2[1];
352        }
353      else if (str[j] == QUOTE_CHAR)
354        {
355          tmp2 = int2hex((unsigned char) QUOTE_CHAR, i2h);
356          tmp[k] = QUOTE_CHAR; ++k;
357          tmp[k] = tmp2[0];    ++k;
358          tmp[k] = tmp2[1];
359        }
360      else
361        {
362          tmp[k] = str[j];
363        }
364      ++k;
365    }
366  SL_RETURN(tmp, _("quote_string"));
367}
368
369static char * unquote_path(char * line, long i)
370{
371  char * tmp  = unquote_string (line, i);
372  size_t len  = sl_strlen(tmp)+1;
373  char * path = SH_ALLOC(len);
374
375  (void) sl_strlcpy (path, tmp, len);
376  if (tmp)
377    SH_FREE(tmp);
378  if (len > 1) {
379    if (path[len-2] == '\n')
380      path[len-2] = '\0';
381  }
382  return path;
383}
384
385/******************************************************************
386 *
387 * Read next record and return it
388 *
389 ******************************************************************/
390
391static void corrupt_record(char * file, int line, const char * filepath)
392{
393  dlog(1, file, line, 
394       _("There is a corrupt record in the file signature database: %s\n"),
395       (NULL == filepath)? _("(null)") : filepath);
396  sh_error_handle ((-1), file, line, 0, MSG_E_SUBGPATH,
397                   _("Corrupt record in file signature database"), 
398                   _("sh_dbIO_getdataent"),
399                   ( (NULL == filepath) ? _("(null)") : filepath) );
400  return;
401}
402
403static void wrong_version(char * file, int line, const char * filepath)
404{
405  dlog(1, file, line, 
406       _("There is a record with a bad version number in the file signature database: %s\n"),
407       (NULL == filepath) ? _("(null)") : filepath);
408  sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGPATH,
409                  _("Record with bad version number in file signature database"), 
410                  _("sh_dbIO_getdataent"),
411                  (NULL == filepath) ? _("(null)") : filepath);
412  return;
413}
414
415static size_t dbIO_fread_struct (sh_filestore_t * ptr, FILE *stream, 
416                                 const char * path, int * errflag)
417{
418  sh_filestore_old_t old_struct;
419  fpos_t position;
420  static int oldflag = -1;
421
422 start:
423  if (oldflag != -1) /* 'initialized' case first */
424    {
425      if (oldflag == 0)
426        return fread (ptr, sizeof(sh_filestore_t), 1, stream);
427
428      else
429        {
430          unsigned short mark;
431          if (1 != fread (&old_struct, sizeof(old_struct), 1, stream))
432            return 0;
433
434          /* set mark to current version */
435          mark = old_struct.mark;
436          mark = *(swap_short(&(mark)));
437          if ((mark & ~REC_FLAGS_MASK) != OLD_REC_MAGIC)
438            {
439              sh_filestore_old_t try_struct;
440              char try[5];
441
442              memset(&try_struct, '\0', sizeof(try_struct));
443              if (!memcmp(&old_struct, &try_struct, sizeof(try_struct)))
444                return 0; /* NULL read */
445              if (1 != fread (try, sizeof(try), 1, stream))
446                return 0;
447              if (feof(stream))
448                return 0;
449
450              wrong_version(FIL__, __LINE__, path);
451              *errflag = -1;
452              return 0;
453            }
454          if ((mark & REC_FLAGS_ATTR) != 0)
455            mark = REC_MAGIC|REC_FLAGS_ATTR;
456          else
457            mark = REC_MAGIC;
458          mark = *(swap_short(&(mark)));
459          old_struct.mark = mark;
460
461          /* copy into current struct version */
462          memcpy(ptr, &old_struct, sizeof(old_struct));
463          ptr->checkflags = 0;
464          return 1;
465        }
466    }
467  else /* not initialized yet, test DB version */
468    {
469      if (0 == fgetpos(stream, &position))
470        {
471          unsigned short mark;
472
473          if (1 != fread (&old_struct, sizeof(old_struct), 1, stream))
474            return 0;
475
476          mark = old_struct.mark;
477          mark = *(swap_short(&(mark)));
478          if ((mark & ~REC_FLAGS_MASK) == REC_MAGIC)
479            oldflag = 0;
480          else if ((mark & ~REC_FLAGS_MASK) == OLD_REC_MAGIC)
481            oldflag = 1;
482          else
483            {
484              wrong_version(FIL__, __LINE__, path);
485              *errflag = -1;
486              return 0;
487            }
488
489          /* return to previous position and read data */
490          if (0 != fsetpos(stream, &position))
491            return 0;
492          goto start;
493        }
494      return 0;
495    }
496}
497
498int sig_end_detected (void * ft)
499{
500  char * str = (char *) ft;
501  char cmp[SH_MINIBUF];
502
503  sl_strlcpy(cmp, _("-----BEGIN PGP SIGNATURE-----"), sizeof(cmp));
504
505  if ( 0 == memcmp(str, cmp, strlen(cmp)) ) 
506    return S_TRUE;
507  return S_FALSE;
508}
509
510static sh_file_t *  sh_dbIO_getdataent (char * line, int size, 
511                                        const char * filepath, int * errflag)
512{
513  sh_file_t * p;
514  sh_filestore_t ft;
515  long i;
516  char * fullpath;
517  char * linkpath;
518  char * attr_string = NULL;
519
520  SL_ENTER(_("sh_dbIO_getdataent"));
521
522  *errflag = 0;
523
524  p = SH_ALLOC(sizeof(sh_file_t));
525
526  /* Read next record -- Part One
527   */
528  if (1 != dbIO_fread_struct (&ft, sh_fin_fd, filepath, errflag))
529    {
530      SH_FREE(p);
531      SL_RETURN( NULL, _("sh_dbIO_getdataent"));
532    }
533
534  ft.mark = *(swap_short(&(ft.mark)));
535
536  if ((ft.mark & ~REC_FLAGS_MASK) != REC_MAGIC)
537    {
538      if (sig_end_detected(&ft))
539        {
540          SH_FREE(p);
541          SL_RETURN( NULL, _("sh_dbIO_getdataent"));
542        }
543      SH_FREE(p);
544      wrong_version(FIL__, __LINE__, filepath);
545      *errflag = -1;
546      SL_RETURN( NULL, _("sh_dbIO_getdataent"));
547    }
548
549  ft.mark = *(swap_short(&(ft.mark)));
550  swap_data(&ft);
551
552  /* Read next record -- Part Two -- Fullpath
553   */
554  i = sh_dbIO_getline (sh_fin_fd, line, size);
555
556  if (i <= 0 ) 
557    {
558      SH_FREE(p);
559      corrupt_record(FIL__, __LINE__, filepath);
560      *errflag = -1;
561      SL_RETURN( NULL, _("sh_dbIO_getdataent"));
562    }
563
564  fullpath = unquote_path(line, i);
565
566  /* Read next record -- Part Three -- Linkpath
567   */
568  i =  sh_dbIO_getline (sh_fin_fd, line, size);
569
570  if (i <= 0 ) 
571    {
572      SH_FREE(fullpath); SH_FREE(p);
573      corrupt_record(FIL__, __LINE__, filepath);
574      *errflag = -1;
575      SL_RETURN( NULL, _("sh_dbIO_getdataent"));
576    }
577
578  linkpath = unquote_path(line, i);
579
580  /* Read next record -- Part Four -- attr_string
581   */
582  if ((ft.mark & REC_FLAGS_ATTR) != 0)
583    {
584      i =  sh_dbIO_getline (sh_fin_fd, line, size);
585      if (i <= 0 ) 
586        {
587          SH_FREE(fullpath); SH_FREE(linkpath); SH_FREE(p);
588          corrupt_record(FIL__, __LINE__, filepath);
589          *errflag = -1;
590          SL_RETURN( NULL, _("sh_dbIO_getdataent"));
591        }
592
593      attr_string = unquote_path(line, i);
594    }
595
596  /* Read next record -- Part Four -- Decode
597   */
598#if defined(SH_STEALTH)
599  sh_do_decode(fullpath,    sl_strlen(fullpath));
600#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
601  sh_do_decode(ft.c_attributes,   sl_strlen(ft.c_attributes));
602#endif
603  sh_do_decode(ft.c_mode,   sl_strlen(ft.c_mode));
604  sh_do_decode(ft.c_owner,  sl_strlen(ft.c_owner));
605  sh_do_decode(ft.c_group,  sl_strlen(ft.c_group));
606  sh_do_decode(ft.checksum, sl_strlen(ft.checksum)); 
607  /*
608   * TXT entries are c_mode[0] != 'l' and do not get decoded
609   */
610  if (ft.c_mode[0] == 'l' && linkpath[0] != '-')
611    { 
612      sh_do_decode(linkpath, sl_strlen(linkpath));
613    }
614  if ((ft.mark & REC_FLAGS_ATTR) != 0)
615    { 
616      sh_do_decode(attr_string, sl_strlen(attr_string));
617    }
618#endif
619
620  memcpy( &(*p).theFile, &ft, sizeof(sh_filestore_t) );
621
622  /* init fflags, such that suid files in
623   * database are recognized as such
624   */
625  {
626    mode_t mode = (mode_t) ft.mode;
627
628    if (S_ISREG(mode) &&
629        (0 !=(S_ISUID & mode) ||
630#if defined(HOST_IS_LINUX)
631         (0 !=(S_ISGID & mode) && 
632          0 !=(S_IXGRP & mode)) 
633#else 
634         0 !=(S_ISGID & mode)
635#endif
636         )
637        )
638      p->fflags = SH_FFLAG_SUIDCHK;
639
640    else
641      p->fflags = 0;
642  }
643
644  p->modi_mask   = ft.checkflags;
645  if (MODI_ISSET(ft.checkflags, MODI_ALLIGNORE))
646    SET_SH_FFLAG_ALLIGNORE(p->fflags);
647  p->fullpath    = fullpath;
648  p->linkpath    = linkpath;
649  p->attr_string = attr_string;
650
651  /* set to an invalid value
652   */
653  ft.mark = (REC_MAGIC + 5);
654
655  SL_REQUIRE((*errflag == 0), _("errflag not set correctly"));
656  SL_RETURN( p, _("sh_dbIO_getdataent"));
657}
658
659/******************************************************************
660 *
661 * Data loading routines
662 *
663 ******************************************************************/
664static SL_TICKET load_data_from_server(const char * uuid)
665{
666  SL_TICKET fd = -1;
667
668#if defined(SH_WITH_CLIENT)
669  char hashbuf[KEYBUF_SIZE];
670
671  /* Data file from Server
672   */
673  if (0 != sl_strcmp(file_path('D', 'R'), _("REQ_FROM_SERVER")))
674    return -1;
675
676  sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_D_DSTART);
677  fd = sh_xfer_request_file((!uuid) ? _("DATA") : uuid);
678
679  if (SL_ISERROR(fd))
680    {
681      if (!uuid)
682        {
683          sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_FBAD);
684          dlog(1, FIL__, __LINE__, 
685               _("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); 
686        }
687      else
688        sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_TCP_FBAD);
689      return fd;
690    }
691  sl_rewind (fd);
692
693  if (!uuid)
694    {
695      sl_strlcpy (sh.data.hash, 
696                  sh_tiger_hash (file_path('D', 'R'), 
697                                 fd, TIGER_NOLIM, hashbuf, sizeof(hashbuf)),
698                  KEY_LEN+1);
699      sl_rewind (fd);
700    }
701#else
702  (void) uuid;
703#endif
704  return fd;
705}
706
707static SL_TICKET load_data_from_disk(const char * filepath)
708{
709  char hashbuf[KEYBUF_SIZE];
710  SL_TICKET fd = -1;
711
712  /* Local data file
713   */
714  if ( SL_ISERROR(fd = sl_open_read(FIL__, __LINE__, filepath, SL_YESPRIV)) )
715    {
716      TPT(( 0, FIL__, __LINE__, _("msg=<Error opening: %s>\n"), filepath));
717      dlog(1, FIL__, __LINE__, 
718    _("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"), 
719           sl_get_errmsg(), fd, (int) sl_ret_euid());
720      sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_EXIT_ABORT1, 
721                       sh.prg_name);
722      return -1;
723    }
724 
725  TPT(( 0, FIL__, __LINE__, _("msg=<Opened database: %s>\n"), 
726        filepath));
727
728  if (sh.data.hash[0] == '\0')
729    {
730      char hashbuf[KEYBUF_SIZE];
731      sl_strlcpy(sh.data.hash, 
732                 sh_tiger_hash (filepath, TIGER_FILE, TIGER_NOLIM, hashbuf, sizeof(hashbuf)), 
733                 KEY_LEN+1);
734    }
735  else
736    {
737      if (0 != sl_strncmp(sh.data.hash, 
738                          sh_tiger_hash (filepath, fd, TIGER_NOLIM, 
739                                         hashbuf, sizeof(hashbuf)),
740                          KEY_LEN)
741          && sh.flag.checkSum != SH_CHECK_INIT) 
742        {
743          dlog(1, FIL__, __LINE__, 
744               _("The checksum of the file signature database has changed since startup: %s -> %s\n"),
745               sh.data.hash, sh_tiger_hash (filepath, fd, TIGER_NOLIM, 
746                                            hashbuf, sizeof(hashbuf)));
747          sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_AUTH,
748                           ( (NULL == filepath) ? _("(null)") :
749                             filepath )
750                           );
751        }
752    }
753  sl_rewind (fd);
754  return fd;
755}
756
757static SL_TICKET verify_data (SL_TICKET fd)
758{
759#if defined(WITH_GPG) || defined(WITH_PGP)
760  SL_TICKET fdTmp;
761
762  /* extract the data and copy to temporary file
763   */
764  fdTmp = sh_gpg_extract_signed(fd);
765
766  if (sig_termfast == 1)  /* SIGTERM */
767    {
768      TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
769      --sig_raised; --sig_urgent;
770      return -1;
771    }
772
773  sl_close(fd);
774  fd = fdTmp;
775
776  /* Validate signature of open file.
777   */
778  if (0 != sh_gpg_check_sign (fd, SIG_DATA))
779    {
780      sl_close(fd);
781      return -1;
782    }
783  sl_rewind (fd);
784#endif
785
786  return fd;
787}
788
789static int read_data(SL_TICKET fd, sh_file_t * tab[TABSIZE], 
790                     const char * filepath)
791{
792  sh_file_t * p;
793  int count = 0;
794  int errflag = 0;
795  char * line = SH_ALLOC(MAX_PATH_STORE+2);
796
797  /* fast forward to start of data
798   */
799  if (0 != sh_dbIO_setdataent(fd, line, MAX_PATH_STORE+1, filepath))
800    return -1;
801
802  while (1) 
803    {
804      if (sig_termfast == 1)  /* SIGTERM */
805        {
806          TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
807          --sig_raised; --sig_urgent;
808          SH_FREE(line);
809          return -1;
810        }
811
812      p = sh_dbIO_getdataent (line, MAX_PATH_STORE+1, filepath, &errflag);
813      if (p != NULL)
814        {
815          if (!sh_hash_is_null_record(&(p->theFile)))
816            hashinsert (tab, p);
817          else
818            sh_hash_remove_unconditional (p->fullpath);
819          ++count;
820        }
821      else
822        break;
823    }
824
825  if (line != NULL)
826    SH_FREE(line);
827
828  /* Always keep db in memory, so we have no open file
829   */
830  sl_close (fd);
831
832  sl_fclose (FIL__, __LINE__, sh_fin_fd);
833  sh_fin_fd = NULL;
834
835  return errflag;
836}
837
838
839static int sh_dbIO_load_db_int(sh_file_t * tab[TABSIZE], 
840                               const char * filepath, const char * uuid)
841{
842#define FGETS_BUF 16384
843
844  SL_TICKET fd = -1;
845
846  if (uuid)
847    {
848      fd = load_data_from_server(uuid);
849      if (SL_ISERROR(fd))
850        return -1;
851    }
852  else if (!filepath)
853    {
854      char * dbpath = file_path('D', 'R');
855
856      fd = load_data_from_server(NULL);
857
858      if (SL_ISERROR(fd))
859        {
860          if (*dbpath == '/')
861            fd = load_data_from_disk(dbpath);
862        }
863    }
864  else
865    {
866      fd = load_data_from_disk(filepath);
867    }
868
869  if (SL_ISERROR(fd))
870    return -1;
871
872  if (sig_termfast == 1)  /* SIGTERM */
873    {
874      TPT((0, FIL__, __LINE__, _("msg=<Terminate.>\n")));
875      --sig_raised; --sig_urgent;
876      aud_exit (FIL__, __LINE__, EXIT_SUCCESS);
877    }
878
879  fd = verify_data(fd);
880  if (SL_ISERROR(fd))
881    return -1;
882
883  if (!uuid) { int i; for (i = 0; i < TABSIZE; ++i) tab[i] = NULL; }
884
885  return read_data (fd, tab, filepath);
886}
887
888
889int sh_dbIO_load_db(sh_file_t * tab[TABSIZE])
890{
891  return sh_dbIO_load_db_int(tab, NULL, NULL);
892}
893int sh_dbIO_load_db_file(sh_file_t * tab[TABSIZE], const char * filepath)
894{
895  return sh_dbIO_load_db_int(tab, filepath, NULL);
896}
897
898int sh_dbIO_load_delta()
899{
900  int    status = 0;
901#if defined(SH_WITH_CLIENT)
902  sh_file_t ** mtab = get_default_data_table();
903  int errflag = 0;
904  unsigned int count;
905  time_t last;
906
907  if ( sh.flag.checkSum != SH_CHECK_INIT )
908    {
909      if (sh_hash_get_initialized() != 0)
910        {
911          char * uuid = sh_socket_get_uuid(&errflag, &count, &last);
912
913          if (!uuid) 
914            return errflag;
915
916          if (count > 0)
917            sh_error_handle(SH_ERR_NOTICE, FIL__, __LINE__, count, MSG_E_SUBGEN,
918                          _("Retrying download of delta DB"), 
919                          _("sh_dbIO_load_delta"));
920
921          status = sh_dbIO_load_db_int(mtab, NULL, uuid);
922          if (status < 0)
923            {
924              /* Return status < 0 indicates that max_try is exceeded
925               */
926              if (sh_socket_return_uuid(uuid, count, last) < 0)
927                sh_error_handle((-1), FIL__, __LINE__, -1, MSG_D_DELTAFAIL, uuid);
928            }
929          else
930            {
931              sh_error_handle((-1), FIL__, __LINE__, -1, MSG_D_DELTAOK, uuid);
932            }
933          SH_FREE(uuid);
934        }
935      else
936        {
937          /* not initialized yet */
938          sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, -1, MSG_E_SUBGEN,
939                          _("Download of delta DB skipped, not initialized yet"), 
940                          _("sh_dbIO_load_delta"));
941          return -1;
942        }
943    }
944#endif
945  return status;
946}
947
948/******************************************************************
949 *
950 * Writing out a file to the database.
951 *
952 ******************************************************************/ 
953static int       pushdata_isfirst =  1;
954static SL_TICKET pushdata_fd      = -1;
955
956static int       pushdata_stdout  =  S_FALSE;
957
958static char * sh_db_version_string = NULL;
959
960int sh_dbIO_writeout_stdout (const char * str)
961{
962  if (!str)
963    { pushdata_stdout  =  S_TRUE; return 0; }
964  return -1;
965}
966
967int sh_dbIO_version_string(const char * str)
968{
969  if (str)
970    {
971      if (sh_db_version_string != NULL) {
972        SH_FREE(sh_db_version_string);
973      }
974      if (0 == sl_strncmp(str, _("NULL"), 4))
975        {
976          sh_db_version_string = NULL;
977          return 0;
978        }
979      sh_db_version_string = sh_util_strdup(str);
980      return 0;
981    }
982  return -1;
983}
984
985void do_writeout_checks(const char * outpath)
986{
987  if ((pushdata_stdout == S_TRUE) && (sh.flag.update == S_TRUE))
988    {
989      dlog(1, FIL__, __LINE__, 
990           _("You cannot write the database to stdout when you use update rather than init.\n"));
991      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
992                      _("Writing database to stdout with update"), 
993                      sh.prg_name, 
994                      _("sh_dbIO_data_write_int"));
995      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
996    }
997
998  if ((pushdata_stdout == S_TRUE) && (sl_is_suid()))
999    {
1000      dlog(1, FIL__, __LINE__, 
1001           _("You cannot write the database to stdout when running with suid privileges.\n"));
1002      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
1003                      _("Writing database to stdout when suid"), 
1004                      sh.prg_name, 
1005                      _("sh_dbIO_data_write_int"));
1006      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1007    }
1008
1009
1010  if ( (pushdata_isfirst == 1) && (pushdata_stdout == S_FALSE) && 
1011       ( (NULL == outpath) || (0 == sl_strcmp(outpath, _("REQ_FROM_SERVER"))) ) )
1012    {
1013      dlog(1, FIL__, __LINE__, 
1014           _("You need to configure a local path for initializing the database\nlike ./configure --with-data-file=REQ_FROM_SERVER/some/local/path\n"));
1015      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORTS,
1016                      _("No local path for database specified"), 
1017                      sh.prg_name, 
1018                      _("sh_dbIO_data_write_int"));
1019      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1020    }
1021
1022  if ((pushdata_isfirst == 1) && (pushdata_stdout == S_FALSE)) 
1023    {
1024      /* Warn that file already exists; file_path != NULL here because
1025       * checked above
1026       */
1027      struct stat sbuf;
1028
1029      if (0 == retry_lstat(FIL__, __LINE__, outpath, &sbuf))
1030        {
1031          if (sh.flag.update == S_FALSE)
1032            {
1033              sh_error_handle((-1), FIL__, __LINE__, 0, MSG_FI_DBEX,
1034                              file_path('D', 'W'));
1035            }
1036        }
1037    }
1038
1039  return;
1040}
1041
1042static SL_TICKET open_writeout_data_truncate(const char * path)
1043{
1044  int status;
1045  SL_TICKET fd;
1046
1047  if ( SL_ISERROR(fd = sl_open_rdwr_trunc(FIL__, __LINE__, path, SL_YESPRIV))) 
1048    {
1049      sh_error_handle((-1), FIL__, __LINE__, fd, MSG_E_ACCESS,
1050                      geteuid(), path);
1051      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1052    }
1053
1054  if (SL_ISERROR(status = sl_lock (fd)))
1055    {
1056      sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
1057                      _("Failed to lock baseline database"), _("sh_dbIO_data_write_int"),
1058                      path);
1059      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1060    }
1061  return fd;
1062}
1063
1064static SL_TICKET open_writeout_data(const char * path)
1065{
1066  int status;
1067  SL_TICKET fd;
1068
1069  if ( SL_ISERROR(fd = sl_open_rdwr(FIL__, __LINE__, path, SL_YESPRIV))) 
1070    {
1071      sh_error_handle((-1), FIL__, __LINE__, fd, MSG_E_ACCESS,
1072                      geteuid(), path);
1073      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1074    }
1075
1076  if (SL_ISERROR(status = sl_lock (fd)))
1077    {
1078      sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
1079                      _("Failed to lock baseline database"), _("sh_dbIO_data_write_int"),
1080                      path);
1081      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1082    }
1083  return fd;
1084}
1085
1086static void seek_writeout_data(SL_TICKET fd, const char * path)
1087{
1088  int status;
1089
1090  if ( SL_ISERROR(status = sl_forward(fd))) 
1091    {
1092      sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGPATH,
1093                      _("Failed to seek to end of baseline database"),
1094                      _("seek_writeout_data"),
1095                      path);
1096      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1097    }
1098  return;
1099}
1100
1101static int seek_writeout_data_old(SL_TICKET fd, const char * path)
1102{
1103  char * line = SH_ALLOC(MAX_PATH_STORE+1);
1104
1105  if (SL_ISERROR(sh_dbIO_setdataent_old (fd, line, MAX_PATH_STORE, path)))
1106    {
1107      SH_FREE(line);
1108      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGPATH,
1109                      _("Failed to seek to end of baseline database"),
1110                      _("seek_writeout_data_old"),
1111                      path);
1112      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1113    }
1114  SH_FREE(line);
1115  return 0;
1116}
1117
1118char * prep_path(char * path, int flag)
1119{
1120  size_t old_len = sl_strlen(path);
1121  char * tmp;
1122  size_t tmp_len;
1123  size_t path_len;
1124  char * outpath = NULL;
1125#if !defined(SH_STEALTH)
1126  (void) flag;
1127#endif
1128
1129#if defined(SH_STEALTH)
1130  if (flag == S_TRUE)
1131    sh_do_encode(path, old_len);
1132#endif
1133  tmp = quote_string(path, old_len);
1134  tmp_len = sl_strlen(tmp);
1135#if defined(SH_STEALTH)
1136  if (flag == S_TRUE)
1137    sh_do_decode(path, old_len);
1138#endif
1139
1140  if (tmp && tmp_len <= MAX_PATH_STORE) 
1141    {
1142      outpath = sh_util_strdup(path);
1143    } 
1144  else 
1145    {
1146      char hashbuf[KEYBUF_SIZE];
1147     
1148      outpath = sh_util_strdup(sh_tiger_hash (path,
1149                                              TIGER_DATA, old_len, 
1150                                              hashbuf, sizeof(hashbuf)));
1151    }
1152  if (tmp) 
1153    SH_FREE(tmp);
1154
1155  path_len = sl_strlen(outpath);
1156#if defined(SH_STEALTH)
1157  if (flag == S_TRUE)
1158    sh_do_encode(outpath, path_len);
1159#endif
1160 
1161  tmp = quote_string(outpath, path_len);
1162  if (tmp) {
1163    SH_FREE(outpath);
1164    outpath = tmp;
1165  }
1166  return outpath;
1167}
1168
1169static char * prep_attr(char * attr_str)
1170{
1171  char * tmp;
1172  char * outstr = NULL;
1173  size_t old_len = sl_strlen(attr_str);
1174
1175#if defined(SH_STEALTH)
1176  sh_do_encode(attr_str, old_len);
1177#endif
1178
1179  tmp = quote_string(attr_str, old_len);
1180  if (tmp)
1181    {
1182      outstr = tmp;
1183    }
1184
1185#if defined(SH_STEALTH)
1186  sh_do_decode(attr_str, old_len);
1187#endif
1188  return outstr;
1189}
1190
1191static void prep_encode(sh_filestore_t * p)
1192{
1193#if defined(SH_STEALTH)
1194  sh_do_encode(p->c_mode,   sl_strlen(p->c_mode));
1195  sh_do_encode(p->c_owner,  sl_strlen(p->c_owner));
1196  sh_do_encode(p->c_group,  sl_strlen(p->c_group));
1197  sh_do_encode(p->checksum, sl_strlen(p->checksum));
1198  sh_do_encode(p->c_attributes,   sl_strlen(p->c_attributes));
1199#else
1200  (void) p;
1201#endif
1202  return;
1203}
1204
1205static void prep_struct(sh_filestore_t * p, file_type * buf, char * fileHash)
1206{
1207#if !defined(__linux__) && !defined(HAVE_STAT_FLAGS)
1208  int    i;
1209#endif
1210  p->mark = REC_MAGIC;
1211  sl_strlcpy(p->c_mode,   buf->c_mode,   CMODE_SIZE);
1212  sl_strlcpy(p->c_group,  buf->c_group,  GROUP_MAX+1);
1213  sl_strlcpy(p->c_owner,  buf->c_owner,  USER_MAX+1);
1214  if (fileHash) {
1215    sl_strlcpy(p->checksum, fileHash,      KEY_LEN+1);
1216  }
1217#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1218  sl_strlcpy(p->c_attributes, buf->c_attributes, ATTRBUF_SIZE);
1219#else
1220  for (i = 0; i < ATTRBUF_USED; ++i) p->c_attributes[i] = '-';
1221  p->c_attributes[ATTRBUF_USED] = '\0';
1222#endif
1223 
1224  prep_encode(p);
1225 
1226#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
1227  p->attributes  = (UINT32) buf->attributes;
1228#else
1229  p->attributes  = 0;
1230#endif
1231  p->linkmode    = (UINT32) buf->linkmode;
1232  p->hardlinks   = (UINT32) buf->hardlinks;
1233  p->dev   = (UINT64) buf->dev;
1234  p->rdev  = (UINT64) buf->rdev;
1235  p->mode  = (UINT32) buf->mode;
1236  p->ino   = (UINT32) buf->ino;
1237  p->size  = (UINT64) buf->size;
1238  p->mtime = (UINT64) buf->mtime;
1239  p->atime = (UINT64) buf->atime;
1240  p->ctime = (UINT64) buf->ctime;
1241  p->owner = (UINT32) buf->owner;
1242  p->group = (UINT32) buf->group;
1243
1244  p->checkflags = (UINT32) buf->check_flags; 
1245 
1246  return;
1247}
1248
1249
1250static void write_start_header(SL_TICKET fd)
1251{
1252  char   timestring[81];
1253
1254  if (pushdata_stdout == S_FALSE)
1255    {
1256      sl_write (fd, _("\n#Host "), 7);
1257      sl_write (fd, sh.host.name, 
1258                sl_strlen(sh.host.name));
1259      sl_write (fd, _(" Version "), 9);
1260      sl_write (fd, sh_db_version_string, 
1261                sl_strlen(sh_db_version_string));
1262      sl_write (fd, _(" Date "), 6);
1263      (void) sh_unix_time(0, timestring, sizeof(timestring));
1264      sl_write (fd, timestring, strlen(timestring));
1265      sl_write (fd,        "\n", 1);
1266    } 
1267  else 
1268    {
1269      printf ("%s",_("\n#Host "));
1270      printf ("%s", sh.host.name);
1271      printf ("%s",_(" Version "));
1272      printf ("%s", sh_db_version_string);
1273      printf ("%s",_(" Date "));
1274      (void) sh_unix_time(0, timestring, sizeof(timestring));
1275      printf ("%s\n", timestring);
1276    }
1277}
1278
1279static void write_start_marker(SL_TICKET fd)
1280{
1281  if (sh_db_version_string != NULL)
1282    {
1283      write_start_header(fd);
1284    }
1285 
1286  if (pushdata_stdout == S_FALSE)
1287    {
1288#if defined(SH_STEALTH)
1289      sl_write      (fd,        "\n", 1);
1290      sl_write_line (fd, N_("[SOF]"), 5);
1291#else
1292      sl_write_line (fd, _("\n[SOF]"),  6);
1293#endif
1294    }
1295  else 
1296    {
1297#if defined(SH_STEALTH)
1298      puts (N_("[SOF]"));
1299#else
1300      puts (_("\n[SOF]"));
1301#endif
1302    }
1303}
1304
1305static void   write_record(SL_TICKET fd, sh_filestore_t * p, 
1306                           char * fullpath, char * linkpath, char * attr_string)
1307{
1308  static char ll[2] = { '-', '\0' };
1309  char * lpath;
1310
1311  if (!linkpath || 0 == sl_strlen(linkpath))
1312    lpath = ll;
1313  else
1314    lpath = linkpath;
1315
1316  if (pushdata_stdout == S_FALSE)
1317    {
1318      sl_write           (fd,        p, sizeof(sh_filestore_t));
1319      sl_write_line_fast (fd, fullpath, sl_strlen(fullpath));
1320      sl_write_line_fast (fd,    lpath, sl_strlen(lpath));
1321      if (attr_string)
1322        sl_write_line_fast (fd, attr_string, sl_strlen(attr_string));
1323    } 
1324  else 
1325    {
1326      if (fwrite (p, sizeof(sh_filestore_t), 1, stdout))
1327        {
1328          puts (fullpath);
1329          puts (lpath);
1330          if (attr_string)
1331            puts (attr_string);
1332        }
1333      else
1334        {
1335          perror(_("Error writing database"));
1336          aud_exit (FIL__, __LINE__, EXIT_FAILURE);
1337        }
1338    }
1339
1340  SH_FREE(fullpath);
1341  if (linkpath)
1342    SH_FREE(linkpath);
1343  if (attr_string)
1344    SH_FREE(attr_string);
1345
1346  return;
1347}
1348
1349static void sh_dbIO_data_write_int (file_type * buf, char * fileHash, 
1350                                    const char * outpath, int truncate)
1351{
1352  static long p_count = 0;
1353  sh_filestore_t p;
1354  char *  fullpath = NULL;
1355  char *  linkpath = NULL;
1356  char *  attr_string = NULL;
1357
1358  SL_ENTER(_("sh_dbIO_data_write_int"));
1359
1360  do_writeout_checks(outpath);
1361
1362  if (sh.flag.update == S_FALSE)
1363    {
1364      if (pushdata_stdout == S_FALSE && pushdata_fd == -1)
1365        {
1366          if (truncate == S_TRUE)
1367            pushdata_fd = open_writeout_data_truncate(outpath);
1368          else
1369            {
1370              pushdata_fd = open_writeout_data(outpath);
1371              seek_writeout_data(pushdata_fd, outpath);
1372            }
1373        }
1374    }
1375  else /* update == TRUE */
1376    {
1377      if (pushdata_isfirst == 1)
1378        {
1379          TPT((0, FIL__, __LINE__, _("msg=<Update.>\n")));
1380          pushdata_fd = open_writeout_data(outpath);
1381          seek_writeout_data_old(pushdata_fd, outpath);
1382        }
1383    }
1384         
1385  if (!buf) {
1386    memset(&p, '\0', sizeof(sh_filestore_t));
1387  }
1388
1389  if (buf != NULL) 
1390    {
1391      fullpath = prep_path(buf->fullpath, S_TRUE);
1392    }
1393
1394  /* NOTE: TXT entries are c_mode[0] != 'l' and do not get decoded
1395   */
1396  if (buf != NULL /* && buf->c_mode[0] == 'l' */ && buf->link_path != NULL) 
1397    { 
1398      if (buf->c_mode[0] == 'l')
1399        linkpath = prep_path(buf->link_path, S_TRUE);
1400      else
1401        linkpath = prep_path(buf->link_path, S_FALSE);
1402    }
1403
1404  if (buf != NULL && buf->attr_string != NULL) 
1405    {
1406      attr_string = prep_attr(buf->attr_string);
1407    }
1408
1409  if (buf != NULL) 
1410    {
1411      prep_struct(&p, buf, fileHash);
1412      if (attr_string)
1413        p.mark |= REC_FLAGS_ATTR;
1414      swap_data(&p);
1415    }
1416
1417  /* write the start marker
1418   */
1419  if (pushdata_isfirst == 1) 
1420    {
1421      if (sh.flag.update == S_FALSE)
1422        write_start_marker(pushdata_fd);
1423      pushdata_isfirst = 0;
1424    }
1425
1426  if (buf && fullpath)
1427    {
1428      write_record(pushdata_fd, &p, fullpath, linkpath, attr_string);
1429      ++p_count;
1430    }
1431
1432  if ((sh.flag.update != S_TRUE) && (pushdata_stdout == S_FALSE))
1433    {
1434      if (sh.flag.checkSum != SH_CHECK_INIT || (buf == NULL && fileHash == NULL))
1435        {
1436          sl_close (pushdata_fd);
1437          pushdata_fd = -1;
1438        }
1439    }
1440
1441  SL_RET0(_("sh_dbIO_data_write_int"));
1442}
1443
1444SH_MUTEX_STATIC(mutex_writeout,PTHREAD_MUTEX_INITIALIZER);
1445
1446void sh_dbIO_data_write (file_type * buf, char * fileHash)
1447{
1448  SH_MUTEX_LOCK(mutex_writeout); 
1449  sh_dbIO_data_write_int (buf, fileHash, file_path('D', 'W'), S_FALSE);
1450  SH_MUTEX_UNLOCK(mutex_writeout); 
1451  return;
1452}
1453
1454
1455static int dbIO_writeout(sh_file_t * mtab[TABSIZE], const char * outpath, int truncate)
1456{
1457  sh_file_t * p;
1458  int         i;
1459  file_type * f;
1460  char   fileHash[KEY_LEN + 1];
1461
1462  SL_ENTER(_("dbIO_writeout"));
1463
1464  SH_MUTEX_LOCK(mutex_writeout); 
1465  if (!SL_ISERROR(pushdata_fd))
1466    {
1467      sl_close(pushdata_fd);
1468      pushdata_fd = -1;
1469    }
1470  pushdata_isfirst =  1;
1471
1472
1473  SH_MUTEX_LOCK(mutex_hash);
1474  for (i = 0; i < TABSIZE; ++i)
1475    {
1476      for (p = mtab[i]; p; p = p->next)
1477        {
1478          f = sh_hash_create_ft (p, fileHash);
1479          sh_dbIO_data_write_int (f, fileHash, outpath, (i == 0) ? truncate : S_FALSE);
1480          if (f->attr_string) SH_FREE(f->attr_string);
1481          if (f->link_path)   SH_FREE(f->link_path);
1482          SH_FREE(f);
1483        }
1484    }
1485  SH_MUTEX_UNLOCK(mutex_hash);
1486
1487  if (!SL_ISERROR(pushdata_fd))
1488    {
1489      sl_close(pushdata_fd);
1490      pushdata_fd = -1;
1491    }
1492  pushdata_isfirst =  1;
1493  SH_MUTEX_UNLOCK(mutex_writeout); 
1494
1495  SL_RETURN (0, _("dbIO_writeout"));
1496}
1497
1498int sh_dbIO_writeout_update()
1499{
1500  sh_file_t ** mtab = get_default_data_table();
1501
1502  if (S_TRUE == file_is_remote())
1503    {
1504      sh_error_handle((-1), FIL__, __LINE__, S_FALSE, MSG_E_SUBGEN, 
1505                      _("Baseline database is remote"), _("sh_dbIO_writeout"));
1506      SL_RETURN (1, _("sh_dbIO_writeout_update"));
1507    }
1508
1509  return dbIO_writeout(mtab, file_path('D', 'W'), S_FALSE);
1510}
1511
1512int sh_dbIO_writeout_to_path(const char * path)
1513{
1514  sh_file_t ** mtab = get_default_data_table();
1515  return dbIO_writeout(mtab, path, S_TRUE);
1516}
1517
1518static void dbIO_write_record(sh_file_t * record, SL_TICKET fd)
1519{
1520  sh_filestore_t * p = &(record->theFile);
1521  char * fullpath    = NULL;
1522  char * linkpath    = NULL;
1523  char * attr_string = NULL;
1524
1525  fullpath = prep_path(record->fullpath, S_TRUE);
1526
1527  /* NOTE: TXT entries are c_mode[0] != 'l' and do not get decoded
1528   */
1529  if (record->linkpath != NULL && 0 != strcmp("-", record->linkpath)) 
1530    { 
1531      if (p->c_mode[0] == 'l')
1532        linkpath = prep_path(record->linkpath, S_TRUE);
1533      else
1534        linkpath = prep_path(record->linkpath, S_FALSE);
1535    }
1536
1537  if (record->attr_string != NULL) 
1538    attr_string = prep_attr(record->attr_string);
1539
1540  prep_encode(p);
1541  swap_data(p);
1542
1543  write_record(fd, p, fullpath, linkpath, attr_string);
1544  return;
1545}
1546
1547static void dbIO_write_entry(sh_file_t * p)
1548{
1549  static int is_first = 1;
1550
1551  if (is_first)
1552    {
1553      pushdata_isfirst =  1;
1554      if (!sh.outpath || sh.outpath[0] == '\0') 
1555        pushdata_stdout  =  S_TRUE;
1556      else
1557        pushdata_fd = open_writeout_data_truncate(sh.outpath);
1558      write_start_marker(pushdata_fd);
1559      pushdata_isfirst = 0;
1560      is_first = 0;
1561    }
1562
1563  dbIO_write_record(p, pushdata_fd);
1564
1565}
1566
1567
1568/******************************************************************
1569 *
1570 * Listing the database.
1571 *
1572 ******************************************************************/ 
1573
1574static int ListBinary = S_FALSE;
1575static char * ListFilter = NULL;
1576
1577int sh_dbIO_list_binary (const char * c)
1578{
1579  (void) c;
1580  ListBinary = S_TRUE;
1581  return 0;
1582}
1583int sh_dbIO_list_filter (const char * c)
1584{
1585  ListFilter = sh_util_strdup(c);
1586  return 0;
1587}
1588
1589#include "zAVLTree.h"
1590
1591static zAVLTree * filter_list = NULL;
1592extern char * rtrim (char * str);
1593
1594#include <ctype.h>
1595static void read_filter()
1596{
1597  int    i, n = 0;
1598  size_t len;
1599  char * key;
1600  char * str;
1601  char * line = SH_ALLOC(SH_MAXBUF);
1602  FILE * fd   = fopen(ListFilter, "r");
1603 
1604  if (!fd)
1605    {
1606      perror(_("read_filter: fopen:"));
1607      _exit(EXIT_FAILURE);
1608    }
1609  do {
1610    i = sh_dbIO_getline (fd, line, SH_MAXBUF);
1611    str = rtrim(line);
1612    while (isspace((int)*str)) ++str;
1613
1614    key = sh_files_parse_input(str, &len);
1615
1616    if (key && *key == '/')
1617      {
1618        zAVL_string_set(&filter_list, key);
1619        ++n;
1620      }
1621  } while (i >= 0);
1622
1623  fclose(fd);
1624  SH_FREE(line);
1625
1626  if (n == 0)
1627    {
1628      fprintf(stderr, _("read_filter: empty file <%s>\n"), ListFilter);
1629      _exit (EXIT_FAILURE);
1630    }
1631  return;
1632}
1633
1634static int check_filter(char * path)
1635{
1636  if (NULL == zAVL_string_get(filter_list, path))
1637    return S_FALSE;
1638  return S_TRUE;
1639}
1640
1641int sh_dbIO_list_db (const char * db_file)
1642{
1643  sh_file_t * p;
1644  SL_TICKET fd;
1645  char * line;
1646  int  errflag = 0;
1647  int  flag = 0;
1648  char * ListFile = get_list_file();
1649
1650  if (!db_file)
1651    {
1652      fputs(_("ERROR: no database file given\n"), stderr);
1653      _exit(EXIT_FAILURE);
1654      return -1; 
1655    }
1656  if (sl_is_suid())
1657    {
1658      fputs(_("ERROR: insufficient privilege\n"), stderr);
1659      _exit (EXIT_FAILURE);
1660      return -1; /* for Mac OSX compiler */
1661    }
1662  if (0 == strcmp(db_file, _("default")))
1663    db_file = file_path('D', 'W');
1664  if (!db_file)
1665    {
1666      fputs(_("ERROR: no filename\n"), stderr);
1667      _exit(EXIT_FAILURE);
1668      return -1; 
1669    }
1670
1671  if (ListFilter) 
1672    read_filter();
1673
1674  line = SH_ALLOC(MAX_PATH_STORE+2);
1675
1676  if ( SL_ISERROR(fd = sl_open_read(FIL__, __LINE__, db_file, SL_YESPRIV))) 
1677    {
1678      fprintf(stderr, _("ERROR: can't open %s for read (errnum = %ld)\n"), 
1679              db_file, fd);
1680      _exit(EXIT_FAILURE);
1681      return -1; 
1682    }
1683
1684  /* fast forward to start of data
1685   */
1686  if (0 != sh_dbIO_setdataent(fd, line, MAX_PATH_STORE+1, db_file))
1687    {
1688      fprintf(stderr, _("ERROR: can't find start marker in %s\n"), 
1689              db_file);
1690      _exit(EXIT_FAILURE);
1691      return -1; 
1692    }
1693
1694  while (1) 
1695    {
1696      p = sh_dbIO_getdataent (line, MAX_PATH_STORE+1, db_file, &errflag);
1697      if ((p != NULL) && (p->fullpath[0] == '/'))
1698        {
1699          if (!ListFile)
1700            {
1701              flag = 1;
1702              if (ListFilter && S_FALSE == check_filter(p->fullpath))
1703                continue;
1704              if (ListBinary)
1705                dbIO_write_entry (p);
1706              else
1707                sh_hash_list_db_entry (p); 
1708            }
1709          else
1710            {
1711              if (0 != sl_strcmp(ListFile, p->fullpath))
1712                {
1713                  continue;
1714                }
1715              flag = 1;
1716              if ('l' != p->theFile.c_mode[0])
1717                {
1718                  if (sh_hash_printcontent(p->linkpath) < 0)
1719                    {
1720                      fputs(_("Error listing file content\n"), stderr);
1721                      _exit(EXIT_FAILURE);
1722                      return -1;
1723                    }
1724                }
1725              else
1726                {
1727                  fputs(_("File is a link\n"), stderr);
1728                  _exit(EXIT_FAILURE);
1729                  return -1;
1730                }
1731              break;
1732            }
1733        }
1734      else if (p == NULL)
1735        {
1736          break;
1737        }
1738    }
1739
1740  if (line != NULL)
1741    SH_FREE(line);
1742  sl_close (fd);
1743
1744  fflush(NULL);
1745
1746  if (flag == 0)
1747    {
1748      fputs(_("File not found.\n"), stderr);
1749      _exit(EXIT_FAILURE);
1750    }
1751  else if (errflag < 0)
1752    {
1753      fputs(_("Error while reading file.\n"), stderr);
1754      _exit(EXIT_FAILURE);
1755    }
1756     
1757  _exit(EXIT_SUCCESS);
1758  return 0; 
1759}
1760
1761/* if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE) */
1762#endif
Note: See TracBrowser for help on using the repository browser.