source: trunk/src/sh_unix.c @ 486

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

Fix for ticket #384 (use logger utility in posix compliant way).

File size: 132.4 KB
Line 
1/* SAMHAIN file system integrity testing                                   */
2/* Copyright (C) 1999 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
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <ctype.h>
27#ifdef HAVE_LINUX_FS_H
28#include <linux/fs.h>
29#endif
30
31#ifdef HAVE_MEMORY_H
32#include <memory.h>
33#endif
34
35#ifdef  HAVE_UNISTD_H
36#include <errno.h>
37#include <signal.h>
38#include <pwd.h>
39#include <grp.h>
40#include <sys/types.h>
41#include <sys/stat.h>
42#include <sys/resource.h>
43#include <fcntl.h>
44#include <unistd.h>
45/* need to undef these, since the #define's may be picked up from
46 * linux/wait.h, and will clash with a typedef in sys/wait.h
47 */
48#undef P_ALL
49#undef P_PID
50#undef P_PGID
51#include <sys/wait.h>
52
53/*********************
54#ifdef HAVE_SYS_VFS_H
55#include <sys/vfs.h>
56#endif
57**********************/
58#endif
59
60#if TIME_WITH_SYS_TIME
61#include <sys/time.h>
62#include <time.h>
63#else
64#if HAVE_SYS_TIME_H
65#include <sys/time.h>
66#else
67#include <time.h>
68#endif
69#endif
70
71#ifdef HAVE_SYS_SELECT_H
72#include <sys/select.h>
73#endif
74
75#ifndef FD_SET
76#define NFDBITS         32
77#define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
78#define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
79#define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
80#endif /* !FD_SET */
81#ifndef FD_SETSIZE
82#define FD_SETSIZE      32
83#endif
84#ifndef FD_ZERO
85#define FD_ZERO(p)      memset((char *)(p), '\0', sizeof(*(p)))
86#endif
87
88
89#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
90#include <sys/mman.h>
91#endif
92
93#include "samhain.h"
94#include "sh_error.h"
95#include "sh_unix.h"
96#include "sh_utils.h"
97#include "sh_mem.h"
98#include "sh_hash.h"
99#include "sh_tools.h"
100#include "sh_restrict.h"
101#include "sh_ipvx.h"
102#include "sh_tiger.h"
103#include "sh_prelink.h"
104#include "sh_pthread.h"
105#include "sh_sem.h"
106
107/* moved here from far below
108 */
109#include <netdb.h>
110
111#define SH_NEED_PWD_GRP
112#define SH_NEED_GETHOSTBYXXX
113#include "sh_static.h"
114
115#ifndef HAVE_LSTAT
116#define lstat   stat
117#endif
118 
119#if defined(S_IFLNK) && !defined(S_ISLNK)
120#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
121#else
122#if !defined(S_ISLNK)
123#define S_ISLNK(mode) (0)
124#endif
125#endif
126
127#if defined(S_IFSOCK) && !defined(S_ISSOCK)
128#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
129#else
130#if !defined(S_ISSOCK)
131#define S_ISSOCK(mode) (0)
132#endif
133#endif
134
135#if defined(S_IFDOOR) && !defined(S_ISDOOR)
136#define S_ISDOOR(mode) (((mode) & S_IFMT) == S_IFDOOR)
137#else
138#if !defined(S_ISDOOR)
139#define S_ISDOOR(mode) (0)
140#endif
141#endif
142
143#if defined(S_IFPORT) && !defined(S_ISPORT)
144#define S_ISPORT(mode) (((mode) & S_IFMT) == S_IFPORT)
145#else
146#if !defined(S_ISPORT)
147#define S_ISPORT(mode) (0)
148#endif
149#endif
150
151#define SH_KEY_NULL _("000000000000000000000000000000000000000000000000")
152
153#undef  FIL__
154#define FIL__  _("sh_unix.c")
155
156unsigned long mask_PRELINK      = MASK_PRELINK_;
157unsigned long mask_USER0        = MASK_USER_;
158unsigned long mask_USER1        = MASK_USER_;
159unsigned long mask_USER2        = MASK_USER_;
160unsigned long mask_USER3        = MASK_USER_;
161unsigned long mask_USER4        = MASK_USER_;
162unsigned long mask_ALLIGNORE    = MASK_ALLIGNORE_;
163unsigned long mask_ATTRIBUTES   = MASK_ATTRIBUTES_;
164unsigned long mask_LOGFILES     = MASK_LOGFILES_;
165unsigned long mask_LOGGROW      = MASK_LOGGROW_;
166unsigned long mask_READONLY     = MASK_READONLY_;
167unsigned long mask_NOIGNORE     = MASK_NOIGNORE_;
168
169
170extern char **environ;
171
172int sh_unix_maskreset()
173{
174  mask_PRELINK      = MASK_PRELINK_;
175  mask_USER0        = MASK_USER_;
176  mask_USER1        = MASK_USER_;
177  mask_USER2        = MASK_USER_;
178  mask_USER3        = MASK_USER_;
179  mask_USER4        = MASK_USER_;
180  mask_ALLIGNORE    = MASK_ALLIGNORE_;
181  mask_ATTRIBUTES   = MASK_ATTRIBUTES_;
182  mask_LOGFILES     = MASK_LOGFILES_;
183  mask_LOGGROW      = MASK_LOGGROW_;
184  mask_READONLY     = MASK_READONLY_;
185  mask_NOIGNORE     = MASK_NOIGNORE_;
186  return 0;
187}
188
189
190#ifdef SYS_SIGLIST_DECLARED
191/* extern const char * const sys_siglist[]; */
192#else
193char * sh_unix_siglist (int signum)
194{
195  switch (signum)
196    {
197#ifdef SIGHUP
198    case SIGHUP: 
199      return _("Hangup");
200#endif
201#ifdef SIGINT
202    case SIGINT: 
203      return _("Interrupt");
204#endif
205#ifdef SIGQUIT
206    case SIGQUIT: 
207      return _("Quit");
208#endif
209#ifdef SIGILL
210    case SIGILL: 
211      return _("Illegal instruction");
212#endif
213#ifdef SIGTRAP
214    case SIGTRAP: 
215      return _("Trace/breakpoint trap");
216#endif
217#ifdef SIGABRT
218    case SIGABRT: 
219      return _("IOT trap/Abort");
220#endif
221#ifdef SIGBUS
222    case SIGBUS: 
223      return _("Bus error");
224#endif
225#ifdef SIGFPE
226    case SIGFPE: 
227      return _("Floating point exception");
228#endif
229#ifdef SIGUSR1
230    case SIGUSR1: 
231      return _("User defined signal 1");
232#endif
233#ifdef SIGSEGV
234    case SIGSEGV: 
235      return _("Segmentation fault");
236#endif
237#ifdef SIGUSR2
238    case SIGUSR2: 
239      return _("User defined signal 2");
240#endif
241#ifdef SIGPIPE
242    case SIGPIPE: 
243      return _("Broken pipe");
244#endif
245#ifdef SIGALRM
246    case SIGALRM: 
247      return _("Alarm clock");
248#endif
249#ifdef SIGTERM
250    case SIGTERM: 
251      return _("Terminated");
252#endif
253#ifdef SIGSTKFLT
254    case SIGSTKFLT: 
255      return _("Stack fault");
256#endif
257#ifdef SIGCHLD
258    case SIGCHLD: 
259      return _("Child exited");
260#endif
261#ifdef SIGCONT
262    case SIGCONT: 
263      return _("Continued");
264#endif
265#ifdef SIGSTOP
266    case SIGSTOP: 
267      return _("Stopped");
268#endif
269#ifdef SIGTSTP
270    case SIGTSTP: 
271      return _("Stop typed at tty");
272#endif
273#ifdef SIGTTIN
274    case SIGTTIN: 
275      return _("Stopped (tty input)");
276#endif
277#ifdef SIGTTOU
278    case SIGTTOU: 
279      return _("Stopped (tty output)");
280#endif
281#ifdef SIGURG
282    case SIGURG: 
283      return _("Urgent condition");
284#endif
285#ifdef SIGXCPU
286    case SIGXCPU: 
287      return _("CPU time limit exceeded");
288#endif
289#ifdef SIGXFSZ
290    case SIGXFSZ: 
291      return _("File size limit exceeded");
292#endif
293#ifdef SIGVTALRM
294    case SIGVTALRM: 
295      return _("Virtual time alarm");
296#endif
297#ifdef SIGPROF
298    case SIGPROF: 
299      return _("Profile signal");
300#endif
301#ifdef SIGWINCH
302    case SIGWINCH: 
303      return _("Window size changed");
304#endif
305#ifdef SIGIO
306    case SIGIO: 
307      return _("Possible I/O");
308#endif
309#ifdef SIGPWR
310    case SIGPWR: 
311      return _("Power failure");
312#endif
313#ifdef SIGUNUSED
314    case SIGUNUSED: 
315      return _("Unused signal");
316#endif
317    }
318  return _("Unknown");
319}
320#endif
321
322
323/* Log from within a signal handler without using any
324 * functions that are not async signal safe.
325 *
326 * This is the safe_itoa helper function.
327 */
328char * safe_itoa(int i, char * str, int size)
329{
330  unsigned int u;
331  int iisneg = 0;
332  char *p = &str[size-1];
333 
334  *p = '\0';
335  if (i < 0) {
336    iisneg = 1;
337    u = ((unsigned int)(-(1+i))) + 1;
338  } else {
339    u = i;
340  }
341  do {
342    --p;
343    *p = '0' + (u % 10);
344    u /= 10;
345  } while (u && (p != str));
346  if ((iisneg == 1) && (p != str)) {
347    --p;
348    *p = '-';
349  }
350  return p;
351}
352
353/* Log from within a signal handler without using any
354 * functions that are not async signal safe.
355 *
356 * This is the safe_logger function.
357 * Arguments: signal (signal number), method (0=logger, 1=stderr), thepid (pid)
358 */
359extern int OnlyStderr; 
360
361int safe_logger (int thesignal, int method, char * details)
362{
363  unsigned int i = 0;
364  int status = -1;
365  struct stat buf;
366  pid_t  newpid;
367  char  str[128];
368  char  * p;
369 
370  char l0[64], l1[64], l2[64], l3[64];
371  char a0[32];
372  char e0[128];
373  char msg[128];
374 
375  char * locations[] = { NULL, NULL, NULL, NULL, NULL };
376  char * envp[]      = { NULL, NULL };
377  char * argp[]      = { NULL, NULL, NULL };
378 
379  pid_t  thepid = getpid();
380 
381  if ((sh.flag.isdaemon == S_FALSE) || (OnlyStderr == S_TRUE))
382    method = 1;
383 
384  /* seems that solaris cc needs this way of initializing ...
385   */
386  locations[0] = l0;
387  locations[1] = l1;
388  locations[2] = l2;
389  locations[3] = l3;
390 
391  envp[0] = e0;
392  argp[0] = a0;
393 
394  sl_strlcpy(msg, _("samhain["), 128);
395  p = safe_itoa((int) thepid, str, 128);
396  if (p && *p)
397    sl_strlcat(msg, p, 128);
398  if (thesignal == 0)
399    {
400      if (details == NULL) {
401        sl_strlcat(msg, _("]: out of memory"), 128);
402      } else {
403        sl_strlcat(msg, _("]: "), 128);
404        sl_strlcat(msg, details, 128);
405      }
406    }
407  else 
408    {
409      sl_strlcat(msg, _("]: exit on signal "), 128);
410      p = safe_itoa(thesignal, str, 128);
411      if (p && *p)
412        sl_strlcat(msg, p, 128);
413    }
414
415  if (method == 1) {
416#ifndef STDERR_FILENO
417#define STDERR_FILENO 2
418#endif
419    int retval = 0;
420    do {
421      retval = write(STDERR_FILENO,  msg, strlen(msg));
422    } while (retval < 0 && errno == EINTR);
423    do {
424      retval = write(STDERR_FILENO, "\n", 1);
425    } while (retval < 0 && errno == EINTR);
426    return 0;
427  }
428
429  sl_strlcpy (l0, _("/usr/bin/logger"), 64);
430  sl_strlcpy (l1, _("/usr/sbin/logger"), 64);
431  sl_strlcpy (l2, _("/usr/ucb/logger"), 64);
432  sl_strlcpy (l3, _("/bin/logger"), 64);
433
434  sl_strlcpy (a0, _("logger"), 32);
435  sl_strlcpy (e0,
436              _("PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/ucb:/usr/local/bin"),
437              128);
438
439  while (locations[i] != NULL) {
440    status = stat(locations[i], &buf);
441    if (status == 0)
442      break;
443    ++i;
444  }
445
446  if (locations[i] != NULL) {
447    argp[1] = msg;
448    newpid = fork();
449    if (newpid == 0) {
450      execve(locations[i], argp, envp);
451      _exit(1);
452    }
453    else if (newpid > 0) {
454      waitpid(newpid, &status, WUNTRACED);
455    }
456  }
457  return 0;
458}
459
460void safe_fatal (const char * details, 
461                 const char * file, int line)
462{
463  char msg[128];
464  char str[128];
465  char * p;
466  int  thesignal = 0;
467  int  method = 0;
468
469  p = safe_itoa((int) line, str, 128);
470  sl_strlcpy(msg, _("FATAL: "), 128);
471  sl_strlcat(msg, file, 128);
472  sl_strlcat(msg, ": ", 128);
473  if (p && (*p)) {
474    sl_strlcat(msg, p   , 128);
475    sl_strlcat(msg, ": ", 128);
476  }
477  sl_strlcat(msg, details, 128);
478  (void) safe_logger (thesignal, method, msg);
479
480  close_ipc ();
481  raise(SIGKILL);
482}
483
484extern char sh_sig_msg[64];
485
486volatile int immediate_exit_normal = 0;
487
488#if defined(SA_SIGACTION_WORKS)
489static
490void sh_unix_sigexit (int mysignal, siginfo_t * signal_info, void * signal_add)
491#else
492static
493void sh_unix_sigexit (int mysignal)
494#endif
495{
496
497#if defined(SA_SIGACTION_WORKS)
498  if (signal_info != NULL && signal_info->si_code == SI_USER && 
499      mysignal != SIGTERM && mysignal != SIGINT) 
500    {
501      return;
502    }
503
504  /* avoid compiler warning (unused var)
505   */
506  (void) signal_add;
507#endif
508
509  /*
510   * Block re-entry
511   */
512  if (immediate_exit_normal > 0)
513    {
514      ++immediate_exit_normal;
515      if ((skey != NULL) && (immediate_exit_normal == 2))
516        memset (skey, '\0', sizeof(sh_key_t));
517      if (immediate_exit_normal == 2)
518        {
519          int val_return;
520
521          do {
522            val_return = chdir ("/");
523          } while (val_return < 0 && errno == EINTR);
524
525          close_ipc ();
526          safe_logger (mysignal, 0, NULL);
527        }
528      raise(SIGKILL);
529    }
530  else
531    {
532      immediate_exit_normal = 1;
533    }
534
535#ifdef SYS_SIGLIST_DECLARED
536  strncpy (sh_sig_msg, sys_siglist[mysignal],     40);
537#else
538  strncpy (sh_sig_msg, sh_unix_siglist(mysignal), 40);
539#endif
540  sh_sig_msg[63] = '\0';
541
542  ++sig_raised;
543  ++sig_urgent;
544  sig_termfast   = 1;
545  return;
546}
547
548volatile int immediate_exit_fast = 0;
549
550#if defined(SA_SIGACTION_WORKS)
551static
552void sh_unix_sigexit_fast (int mysignal, siginfo_t * signal_info, 
553                           void * signal_add)
554#else
555static
556void sh_unix_sigexit_fast (int mysignal)
557#endif
558{
559#if defined(SL_DEBUG) && (defined(USE_SYSTEM_MALLOC) || !defined(USE_MALLOC_LOCK))
560  int retval;
561#endif
562
563#if defined(SA_SIGACTION_WORKS)
564  if (signal_info != NULL && signal_info->si_code == SI_USER)
565    {
566      return;
567    }
568#endif
569
570  /* avoid compiler warning (unused var)
571   */
572#if defined(SA_SIGACTION_WORKS)
573  (void) signal_add;
574#endif
575
576  /* Check whether the heap is ok; otherwise _exit
577   */
578#if !defined(SL_DEBUG) || (!defined(USE_SYSTEM_MALLOC) && defined(USE_MALLOC_LOCK))
579  ++immediate_exit_fast;
580  if (skey != NULL && immediate_exit_fast < 2)
581    memset (skey, '\0', sizeof(sh_key_t));
582  if (immediate_exit_fast < 2)
583    safe_logger (mysignal, 0, NULL);
584  raise(SIGKILL);
585#else
586
587  /* debug code
588   */
589  if (immediate_exit_fast == 1)
590    {
591      ++immediate_exit_fast;
592      if (skey != NULL)
593        memset (skey, '\0', sizeof(sh_key_t));
594      close_ipc ();
595      safe_logger (mysignal, 0, NULL);
596      do {
597        retval = chdir ("/");
598      } while (retval < 0 && errno == EINTR);
599      raise(SIGFPE);
600    }
601  else if (immediate_exit_fast == 2)
602    {
603      do {
604        retval = chdir ("/");
605      } while (retval < 0 && errno == EINTR);
606      raise(SIGFPE);
607    }
608  else if (immediate_exit_fast != 0)
609    {
610      raise(SIGKILL);
611    }
612
613  ++immediate_exit_fast;
614 
615  /* The FPE|BUS|SEGV|ILL signals leave the system in an undefined
616   * state, thus it is best to exit immediately.
617   */
618#ifdef SYS_SIGLIST_DECLARED
619  strncpy (sh_sig_msg, sys_siglist[mysignal],     40);
620#else
621  strncpy (sh_sig_msg, sh_unix_siglist(mysignal), 40);
622#endif
623  sh_sig_msg[63] = '\0';
624
625  sl_stack_print();
626
627  /* Try to push out an error message.
628   */
629  sh_error_handle ((-1), FIL__, __LINE__, mysignal, MSG_EXIT_NORMAL, 
630                   sh.prg_name, sh_sig_msg);
631
632  if (skey != NULL)
633    memset (skey, '\0', sizeof(sh_key_t));
634  close_ipc ();
635
636  do {
637    retval = chdir ("/");
638  } while (retval < 0 && errno == EINTR);
639
640  raise(SIGFPE);
641#endif
642}
643
644
645static
646void sh_unix_sigaction (int mysignal)
647{
648  ++sig_raised;
649#ifdef SIGUSR1
650  if (mysignal == SIGUSR1)
651    sig_debug_switch       = 1;
652#endif
653#ifdef SIGUSR2
654  if (mysignal == SIGUSR2)
655    {
656      ++sig_suspend_switch;
657      ++sig_urgent;
658    }
659#endif
660#ifdef SIGHUP
661  if (mysignal == SIGHUP)
662    sig_config_read_again = 1;
663#endif
664#ifdef SIGTTOU
665  if (mysignal == SIGTTOU) {
666    sig_force_check = 1; sh_sem_trylock(); }
667#endif
668#ifdef SIGTTIN
669  if (mysignal == SIGTTIN)
670    sig_fresh_trail = 1;
671#endif
672#ifdef SIGABRT
673  if (mysignal == SIGABRT)
674    sig_fresh_trail       = 1;
675#endif
676#ifdef SIGQUIT
677  if (mysignal == SIGQUIT)
678    sig_terminate       = 1;
679#endif
680#ifdef SIGTERM
681  if (mysignal == SIGTERM)
682    {
683      strncpy (sh_sig_msg, _("Terminated"), 40);
684      sig_termfast          = 1;
685      ++sig_urgent;
686    }
687#endif
688
689  return;
690}
691
692void sh_unix_ign_sigpipe()
693{
694  struct sigaction ignact;
695
696  ignact.sa_handler = SIG_IGN;            /* signal action           */
697  sigemptyset( &ignact.sa_mask );         /* set an empty mask       */
698  ignact.sa_flags = 0;                    /* init sa_flags           */
699
700#ifdef SIGPIPE
701  retry_sigaction(FIL__, __LINE__, SIGPIPE,   &ignact, NULL);
702#endif
703
704  return;
705}
706static
707void sh_unix_siginstall (int goDaemon)
708{
709  struct sigaction act, act_fast, act2, oldact, ignact;
710#if defined (SH_WITH_SERVER)
711  (void) goDaemon;
712#endif
713
714  SL_ENTER(_("sh_unix_siginstall"));
715
716  ignact.sa_handler = SIG_IGN;            /* signal action           */
717  sigemptyset( &ignact.sa_mask );         /* set an empty mask       */
718  ignact.sa_flags = 0;                    /* init sa_flags           */
719
720#if defined(SA_SIGACTION_WORKS)
721  act.sa_sigaction = &sh_unix_sigexit;    /* signal action           */
722#else
723  act.sa_handler   = &sh_unix_sigexit;    /* signal action           */
724#endif
725
726  sigfillset ( &act.sa_mask );            /* set a  full mask        */
727
728
729  /* Block all but deadly signals.
730   */
731#ifdef SIGILL
732  sigdelset  ( &act.sa_mask, SIGILL  );
733#endif
734#ifndef SL_DEBUG
735#ifdef SIGFPE
736  sigdelset  ( &act.sa_mask, SIGFPE  );
737#endif
738#endif
739#ifdef SIGSEGV
740  sigdelset  ( &act.sa_mask, SIGSEGV );
741#endif
742#ifdef SIGBUS
743  sigdelset  ( &act.sa_mask, SIGBUS  );
744#endif
745
746#if defined(SA_SIGACTION_WORKS)
747  act_fast.sa_sigaction = &sh_unix_sigexit_fast;  /* signal action           */
748#else
749  act_fast.sa_handler   = &sh_unix_sigexit_fast;  /* signal action           */
750#endif
751
752  sigfillset ( &act_fast.sa_mask );               /* set a full mask         */
753
754#ifdef SIGILL
755  sigdelset  ( &act_fast.sa_mask, SIGILL  );
756#endif
757#ifndef SL_DEBUG
758#ifdef SIGFPE
759  sigdelset  ( &act_fast.sa_mask, SIGFPE  );
760#endif
761#endif
762#ifdef SIGSEGV
763  sigdelset  ( &act_fast.sa_mask, SIGSEGV );
764#endif
765#ifdef SIGBUS
766  sigdelset  ( &act_fast.sa_mask, SIGBUS  );
767#endif
768
769
770  /* Use siginfo to verify origin of signal, if possible.
771   */
772#if defined(SA_SIGACTION_WORKS)
773  act.sa_flags      = SA_SIGINFO;
774  act_fast.sa_flags = SA_SIGINFO;
775#else
776  act.sa_flags      = 0;
777  act_fast.sa_flags = 0;
778#endif
779
780  /* Do not block the signal from being received in its handler ...
781   * (is this a good or a bad idea ??).
782   */
783#if   defined(SA_NOMASK)
784  act_fast.sa_flags |= SA_NOMASK;
785#elif defined(SA_NODEFER)
786  act_fast.sa_flags |= SA_NODEFER;
787#endif
788
789
790  act2.sa_handler = &sh_unix_sigaction;  /* signal action           */
791  sigemptyset( &act2.sa_mask );          /* set an empty mask       */
792  act2.sa_flags = 0;                     /* init sa_flags           */
793
794  /* signals to control the daemon */
795
796#ifdef SIGHUP
797  retry_sigaction(FIL__, __LINE__, SIGHUP,     &act2, &oldact);
798#endif
799#ifdef SIGABRT
800  retry_sigaction(FIL__, __LINE__, SIGABRT,    &act2, &oldact);
801#endif
802#ifdef SIGUSR1
803  retry_sigaction(FIL__, __LINE__, SIGUSR1,    &act2, &oldact);
804#endif
805#ifdef SIGUSR2
806  retry_sigaction(FIL__, __LINE__, SIGUSR2,    &act2, &oldact);
807#endif
808#ifdef SIGQUIT
809  retry_sigaction(FIL__, __LINE__, SIGQUIT,    &act2, &oldact);
810#endif
811#ifdef SIGTERM
812  retry_sigaction(FIL__, __LINE__, SIGTERM,    &act,  &oldact);
813#endif
814
815  /* fatal signals that may cause termination */
816
817#ifdef SIGILL
818  retry_sigaction(FIL__, __LINE__, SIGILL,  &act_fast, &oldact);
819#endif
820#ifndef SL_DEBUG
821#ifdef SIGFPE
822  retry_sigaction(FIL__, __LINE__, SIGFPE,  &act_fast, &oldact);
823#endif
824#endif
825#ifdef SIGSEGV
826  retry_sigaction(FIL__, __LINE__, SIGSEGV, &act_fast, &oldact);
827#endif
828#ifdef SIGBUS
829  retry_sigaction(FIL__, __LINE__, SIGBUS,  &act_fast, &oldact);
830#endif
831
832  /* other signals  */
833
834#ifdef SIGINT
835  retry_sigaction(FIL__, __LINE__, SIGINT,       &act, &oldact);
836#endif
837#ifdef SIGPIPE
838  retry_sigaction(FIL__, __LINE__, SIGPIPE,   &ignact, &oldact);
839#endif
840#ifdef SIGALRM
841  retry_sigaction(FIL__, __LINE__, SIGALRM,   &ignact, &oldact);
842#endif
843#ifdef SIGTSTP
844  retry_sigaction(FIL__, __LINE__, SIGTSTP,   &ignact, &oldact);
845#endif
846
847#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
848#ifdef SIGTTOU
849  if (goDaemon == 1)
850    retry_sigaction(FIL__, __LINE__, SIGTTOU,     &act2, &oldact);
851  else
852    retry_sigaction(FIL__, __LINE__, SIGTTOU,   &ignact, &oldact);
853#endif
854#ifdef SIGTTIN
855  if (goDaemon == 1)
856    retry_sigaction(FIL__, __LINE__, SIGTTIN,     &act2, &oldact);
857  else
858    retry_sigaction(FIL__, __LINE__, SIGTTIN,   &ignact, &oldact);
859#endif
860#else
861#ifdef SIGTTOU
862  retry_sigaction(FIL__, __LINE__, SIGTTOU,   &ignact, &oldact);
863#endif
864#ifdef SIGTTIN
865  retry_sigaction(FIL__, __LINE__, SIGTTIN,   &ignact, &oldact);
866#endif
867#endif
868
869#ifdef SIGTRAP
870#if !defined(SCREW_IT_UP)
871  retry_sigaction(FIL__, __LINE__, SIGTRAP,      &act, &oldact);
872#endif
873#endif
874
875#ifdef SIGPOLL
876  retry_sigaction(FIL__, __LINE__, SIGPOLL,   &ignact, &oldact);
877#endif
878#if defined(SIGPROF) && !defined(SH_PROFILE)
879  retry_sigaction(FIL__, __LINE__, SIGPROF,   &ignact, &oldact);
880#endif
881#ifdef SIGSYS
882  retry_sigaction(FIL__, __LINE__, SIGSYS,       &act, &oldact);
883#endif
884#ifdef SIGURG
885  retry_sigaction(FIL__, __LINE__, SIGURG,    &ignact, &oldact);
886#endif
887#if defined(SIGVTALRM) && !defined(SH_PROFILE)
888  retry_sigaction(FIL__, __LINE__, SIGVTALRM, &ignact, &oldact);
889#endif
890#ifdef SIGXCPU
891  retry_sigaction(FIL__, __LINE__, SIGXCPU,      &act, &oldact);
892#endif
893#ifdef SIGXFSZ
894  retry_sigaction(FIL__, __LINE__, SIGXFSZ,      &act, &oldact);
895#endif
896
897#ifdef SIGEMT
898  retry_sigaction(FIL__, __LINE__, SIGEMT,    &ignact, &oldact);
899#endif
900#ifdef SIGSTKFLT
901  retry_sigaction(FIL__, __LINE__, SIGSTKFLT,    &act, &oldact);
902#endif
903#ifdef SIGIO
904  retry_sigaction(FIL__, __LINE__, SIGIO,     &ignact, &oldact);
905#endif
906#ifdef SIGPWR
907  retry_sigaction(FIL__, __LINE__, SIGPWR,       &act, &oldact);
908#endif
909
910#ifdef SIGLOST
911  retry_sigaction(FIL__, __LINE__, SIGLOST,   &ignact, &oldact);
912#endif
913#ifdef SIGUNUSED
914  retry_sigaction(FIL__, __LINE__, SIGUNUSED, &ignact, &oldact);
915#endif
916
917  SL_RET0(_("sh_unix_siginstall"));
918}
919
920/* ---------------------------------------------------------------- */
921
922/* checksum the own binary
923 */
924int sh_unix_self_hash (const char * c)
925{
926  char message[512];
927  char hashbuf[KEYBUF_SIZE];
928
929  SL_ENTER(_("sh_unix_self_hash"));
930
931  if (c == NULL)
932    {
933      sh.exec.path[0] = '\0';
934      SL_RETURN((0), _("sh_unix_self_hash"));
935    }
936  sl_strlcpy(sh.exec.path, c, SH_PATHBUF);
937
938  sl_strlcpy(sh.exec.hash,
939             sh_tiger_hash (c, TIGER_FILE, TIGER_NOLIM, hashbuf, sizeof(hashbuf)), 
940             KEY_LEN+1);
941  sl_snprintf(message, 512, _("%s has checksum: %s"),
942              sh.exec.path, sh.exec.hash);
943  message[511] = '\0';
944  sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
945                  message, _("sh_unix_self_hash"));
946  if (0 == sl_strcmp(sh.exec.hash, SH_KEY_NULL ))
947    {
948      dlog(1, FIL__, __LINE__, 
949           _("Could not checksum my own executable because of the\nfollowing error: %s: %s\n\nPossible reasons include:\n  Wrong path in configure file option SamhainPath=/path/to/executable\n  No read permission for the effective UID: %d\n"), 
950           sh.exec.path, sl_get_errmsg(), (int) sl_ret_euid());
951      sh_error_handle ((-1), FIL__, __LINE__, EACCES, MSG_NOACCESS,
952                       (long) sh.real.uid, c);
953      aud_exit (FIL__, __LINE__, EXIT_FAILURE);
954    }
955  SL_RETURN((0), _("sh_unix_self_hash"));
956}
957
958int sh_unix_self_check ()
959{
960  char newhash[KEY_LEN+1];
961  char message[512];
962  char hashbuf[KEYBUF_SIZE];
963
964  SL_ENTER(_("sh_unix_self_check"));
965  if (sh.exec.path[0] == '\0')
966    SL_RETURN((0), _("sh_unix_self_check"));
967
968  sl_strlcpy(newhash, 
969             sh_tiger_hash (sh.exec.path, TIGER_FILE, TIGER_NOLIM, hashbuf, sizeof(hashbuf)), 
970             KEY_LEN+1);
971  if (0 == sl_strncmp(sh.exec.hash, 
972                      newhash,
973                      KEY_LEN))
974    SL_RETURN((0), _("sh_unix_self_check"));
975
976 
977  dlog(1, FIL__, __LINE__, 
978       _("The checksum of the executable: %s has changed since startup (%s -> %s).\n"),
979       sh.exec.path, sh.exec.hash, newhash);
980
981  sl_snprintf(message, 512, 
982              _("The checksum of %s has changed since startup (%s -> %s)"),
983              sh.exec.path, sh.exec.hash, newhash);
984  message[511] = '\0';
985
986  sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
987                  message, _("sh_unix_self_check"));
988  sh_error_handle ((-1), FIL__, __LINE__, EACCES, MSG_E_AUTH,
989                   sh.exec.path);
990  SL_RETURN((-1), _("sh_unix_self_check"));
991}
992
993
994/* ---------------------------------------------------------------- */
995
996long sh_group_to_gid (const char * g, int * fail)
997{
998  struct group *           w;
999  gid_t                    gid  = 0;
1000  int                      status = 0;
1001
1002#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1003  struct group     grp;
1004  char           * buffer;
1005  static size_t    gbufsize = SH_GRBUF_SIZE;       
1006#endif
1007
1008  *fail = -1;
1009
1010  if (g)
1011    {
1012      size_t i;
1013      size_t len = strlen(g);
1014
1015      *fail = 0;
1016
1017      for (i = 0; i < len; ++i)
1018        {
1019          char c = g[i];
1020
1021          if (!isdigit((int) c))
1022            goto is_a_name;
1023        }
1024      return atol(g);
1025
1026    is_a_name:
1027
1028#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1029
1030      buffer = SH_ALLOC(gbufsize);
1031      status = sh_getgrnam_r(g, &grp, buffer, gbufsize, &w);
1032
1033      if ((status == ERANGE) && (w == NULL)) 
1034        {
1035          if (S_TRUE ==  sl_ok_adds( gbufsize, SH_GRBUF_SIZE ))
1036            {
1037              SH_FREE(buffer);
1038              gbufsize += SH_GRBUF_SIZE;
1039              goto is_a_name;
1040            }
1041        }
1042
1043#else
1044
1045      errno = 0;
1046      w = sh_getgrnam(g);
1047      status = errno;
1048
1049#endif
1050
1051      if ((status == ERANGE) && (w == NULL)) 
1052        {
1053          static int seen = 0;
1054         
1055          if (seen == 0)
1056            {
1057              char errbuf[SH_ERRBUF_SIZE];
1058
1059              sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_GRNULL,
1060                               sh_error_message(status, errbuf, sizeof(errbuf)),
1061                               _("sh_group_to_gid"), (long) -1, _("line too long in group entry"));
1062              ++seen;
1063            }
1064          *fail = -1;
1065        }
1066      else if (w == NULL)
1067        {
1068          char * tmp = sh_util_strdup(g);
1069          sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS, 
1070                           _("sh_group_to_gid"), tmp);
1071          SH_FREE(tmp);
1072          *fail = -1;
1073        }
1074      else
1075        {
1076          gid = w->gr_gid;
1077        }
1078#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1079      SH_FREE(buffer);
1080#endif
1081    }
1082
1083  return gid;
1084}
1085
1086/* ---------------------------------------------------------------- */
1087
1088
1089/* added    Tue Feb 22 10:36:44 NFT 2000 Rainer Wichmann            */
1090static int tf_add_trusted_user_int(const char * c)
1091{
1092  struct passwd *          w;
1093  int                           count;
1094  uid_t                     pwid  = (uid_t)-1;
1095
1096#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1097  struct passwd    pwd;
1098  char           * buffer;
1099#endif
1100 
1101  SL_ENTER(_("tf_add_trusted_user_int"));
1102
1103  /* First check for a user name.
1104   */
1105#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1106  buffer = SH_ALLOC(SH_PWBUF_SIZE);
1107  sh_getpwnam_r(c, &pwd, buffer, SH_PWBUF_SIZE, &w);
1108#else
1109  w = sh_getpwnam(c);
1110#endif
1111
1112  if ((w != NULL) && ((pwid = w->pw_uid) > 0))
1113    goto succe;
1114       
1115  /* Failed, so check for a numerical value.
1116   */
1117  pwid = strtol(c, (char **)NULL, 10);
1118  if (pwid > 0 && pwid < 65535)
1119    goto succe;
1120     
1121  sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS, 
1122                   _("add trusted user"), c);
1123#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1124  SH_FREE(buffer);
1125#endif
1126  SL_RETURN((-1), _("tf_add_trusted_user_int"));
1127
1128 succe:
1129  count = sl_trust_add_user(pwid);
1130#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1131  SH_FREE(buffer);
1132#endif
1133  SL_RETURN((count), _("tf_add_trusted_user_int"));
1134}
1135
1136int tf_add_trusted_user(const char * c)
1137{
1138  int    i;
1139  char * q;
1140  char * p = sh_util_strdup (c);
1141#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
1142  char * saveptr;
1143#endif
1144
1145  SL_ENTER(_("tf_add_trusted_user"));
1146
1147#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
1148  q = strtok_r(p, ", \t", &saveptr);
1149#else
1150  q = strtok(p, ", \t");
1151#endif
1152  if (!q)
1153    {
1154      SH_FREE(p);
1155      SL_RETURN((-1), _("tf_add_trusted_user"));
1156    }
1157  while (q)
1158    {
1159      i = tf_add_trusted_user_int(q);
1160      if (SL_ISERROR(i))
1161        {
1162          SH_FREE(p);
1163          SL_RETURN((i), _("tf_add_trusted_user"));
1164        }
1165#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
1166      q = strtok_r(NULL, ", \t", &saveptr);
1167#else
1168      q = strtok(NULL, ", \t");
1169#endif
1170    }
1171  SH_FREE(p);
1172  SL_RETURN((0), _("tf_add_trusted_user"));
1173}
1174
1175extern uid_t   sl_trust_baduid(void);
1176extern gid_t   sl_trust_badgid(void);
1177
1178#if defined(HOST_IS_CYGWIN) || defined(__cygwin__) || defined(__CYGWIN32__) || defined(__CYGWIN__)
1179int tf_trust_check (const char * file, int mode)
1180{
1181  (void) file;
1182  (void) mode;
1183  return 0;
1184}
1185#else
1186int tf_trust_check (const char * file, int mode)
1187{
1188  char * tmp;
1189  char * tmp2;
1190  char * p;
1191  int    status;
1192  int    level;
1193  uid_t  ff_euid = (uid_t) -1;
1194
1195  SL_ENTER(_("tf_trust_check"));
1196
1197  if (mode == SL_YESPRIV)
1198    sl_get_euid(&ff_euid);
1199  else
1200    sl_get_ruid(&ff_euid);
1201
1202#if defined(SH_WITH_SERVER)
1203  if (0 == sl_ret_euid())   /* privileges not dropped yet */
1204    {
1205#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1206      struct passwd    pwd;
1207      char          *  buffer = SH_ALLOC(SH_PWBUF_SIZE);
1208      struct passwd *  tempres;
1209      sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
1210#else
1211      struct passwd * tempres = sh_getpwnam(DEFAULT_IDENT);
1212#endif
1213
1214      if (!tempres)
1215        {
1216          dlog(1, FIL__, __LINE__, 
1217               _("User %s does not exist. Please add the user to your system.\n"), 
1218               DEFAULT_IDENT);
1219          aud_exit (FIL__, __LINE__, EXIT_FAILURE);
1220        }
1221      else
1222        {
1223          ff_euid = tempres->pw_uid;
1224        }
1225#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R)
1226      SH_FREE(buffer);
1227#endif
1228    }
1229#endif
1230
1231  status = sl_trustfile_euid(file, ff_euid);
1232
1233  if ( SL_ENONE != status) 
1234    {
1235      if (status == SL_ESTAT) 
1236        level = SH_ERR_ALL;
1237      else
1238        level = SH_ERR_ERR;
1239
1240      tmp  = sh_util_safe_name (file);
1241      p    = sl_trust_errfile();
1242      if (p && *p != '\0')
1243        {
1244          tmp2  = sh_util_safe_name (sl_trust_errfile());
1245          sh_error_handle(level, FIL__, __LINE__, status, MSG_E_TRUST2,
1246                          sl_error_string(status), tmp, tmp2);
1247          SH_FREE(tmp2); 
1248        }
1249      else
1250        {
1251          sh_error_handle(level, FIL__, __LINE__, status, MSG_E_TRUST1,
1252                          sl_error_string(status), tmp);
1253        }
1254      SH_FREE(tmp);
1255
1256      if (status == SL_EBADUID   || status == SL_EBADGID || 
1257          status == SL_EBADOTH   || status == SL_ETRUNC  || 
1258          status == SL_EINTERNAL )
1259        {
1260          switch (status) {
1261          case SL_EINTERNAL:
1262            dlog(1, FIL__, __LINE__, 
1263                 _("An internal error occured in the trustfile function.\n"));
1264            break;
1265          case SL_ETRUNC:
1266            tmp  = sh_util_safe_name (file);
1267            dlog(1, FIL__, __LINE__, 
1268                 _("A filename truncation occured in the trustfile function.\nProbably the normalized filename for %s\nis too long. This may be due e.g. to deep or circular softlinks.\n"), 
1269                 tmp);
1270            SH_FREE(tmp);
1271            break;
1272          case SL_EBADOTH:
1273            tmp  = sh_util_safe_name (file);
1274            p    = sl_trust_errfile();
1275            dlog(1, FIL__, __LINE__, 
1276                 _("The path element: %s\nin the filename: %s is world writeable.\n"),
1277                 p, tmp);
1278            SH_FREE(tmp);
1279            break;
1280          case SL_EBADUID:
1281            tmp  = sh_util_safe_name (file);
1282            p    = sl_trust_errfile();
1283            dlog(1, FIL__, __LINE__, 
1284                 _("The owner (UID = %ld) of the path element: %s\nin the filename: %s\nis not in the list of trusted users.\nTo fix the problem, you can:\n - run ./configure again with the option --with-trusted=0,...,UID\n   where UID is the UID of the untrusted user, or\n - use the option TrustedUser=UID in the configuration file.\n"),
1285                 (UID_CAST)sl_trust_baduid(), p, tmp);
1286            SH_FREE(tmp);
1287            break;
1288          case SL_EBADGID:
1289            tmp  = sh_util_safe_name (file);
1290            p    = sl_trust_errfile();
1291            dlog(1, FIL__, __LINE__, 
1292                 _("The path element: %s\nin the filename: %s\nis group writeable (GID = %ld), and at least one of the group\nmembers (UID = %ld) is not in the list of trusted users.\nTo fix the problem, you can:\n - run ./configure again with the option --with-trusted=0,...,UID\n   where UID is the UID of the untrusted user, or\n - use the option TrustedUser=UID in the configuration file.\n"),
1293                 p, tmp, (UID_CAST)sl_trust_badgid(), 
1294                 (UID_CAST)sl_trust_baduid());
1295            SH_FREE(tmp);
1296            break;
1297          default:
1298            break;
1299          }
1300           
1301          SL_RETURN((-1), _("tf_trust_check"));
1302        }
1303    }
1304
1305  SL_RETURN((0), _("tf_trust_check"));
1306}
1307#endif
1308
1309#ifdef HAVE_INITGROUPS
1310#ifdef HOST_IS_OSF
1311int  sh_unix_initgroups (      char * in_user, gid_t in_gid)
1312#else
1313int  sh_unix_initgroups (const char * in_user, gid_t in_gid)
1314#endif
1315{
1316  int status  = -1;
1317  status = sh_initgroups (in_user, in_gid);
1318  if (status < 0)
1319    {
1320      if (errno == EPERM)
1321        return 0;
1322      if (errno == EINVAL)
1323        return 0;
1324      return -1;
1325    }
1326  return 0;
1327}
1328#else
1329int  sh_unix_initgroups (const char * in_user, gid_t in_gid)
1330{
1331  (void) in_user;
1332  (void) in_gid;
1333  return 0;
1334}
1335#endif
1336
1337#ifdef HAVE_INITGROUPS
1338char *  sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len);
1339int  sh_unix_initgroups2 (uid_t in_pid, gid_t in_gid)
1340{
1341  int status  = -1;
1342  char user[SH_MINIBUF];
1343
1344  SL_ENTER(_("sh_unix_initgroups2"));
1345
1346  if (NULL == sh_unix_getUIDname (SH_ERR_ERR, in_pid, user, sizeof(user)))
1347    SL_RETURN((-1), _("sh_unix_initgroups2"));
1348  status = sh_initgroups (user, in_gid);
1349  if (status < 0)
1350    {
1351      if (errno == EPERM)
1352        status = 0;
1353      if (errno == EINVAL)
1354        status = 0;
1355    }
1356  SL_RETURN((status), _("sh_unix_initgroups2"));
1357}
1358#else
1359int  sh_unix_initgroups2 (uid_t in_pid, gid_t in_gid)
1360{
1361  (void) in_pid;
1362  (void) in_gid;
1363  return 0;
1364}
1365#endif
1366
1367void sh_unix_closeall (int fd, int except, int inchild)
1368{
1369  int fdx = fd;
1370#ifdef _SC_OPEN_MAX
1371  int fdlimit = sysconf (_SC_OPEN_MAX);
1372#else
1373#ifdef OPEN_MAX
1374  int fdlimit = OPEN_MAX;
1375#else
1376  int fdlimit = _POSIX_OPEN_MAX;
1377#endif
1378#endif
1379
1380  SL_ENTER(_("sh_unix_closeall"));
1381
1382  /* can't happen - so fix it :-(
1383   */
1384  if (fdlimit < 0)
1385    fdlimit = 20;  /* POSIX lower limit */
1386
1387  if (fdlimit > 65536)
1388    fdlimit = 65536;
1389
1390  if (!inchild)
1391    sl_dropall (fdx, except);
1392  else
1393    sl_dropall_dirty (fdx, except);
1394
1395  /* Close everything from fd (inclusive) up to fdlimit (exclusive).
1396   */
1397  while (fd < fdlimit)
1398    {
1399      if (fd == except)
1400        fd++;
1401      else if (slib_do_trace != 0 && fd == slib_trace_fd)
1402        fd++;
1403      else
1404        sl_close_fd(FIL__, __LINE__, fd++);
1405    }
1406
1407  SL_RET0(_("sh_unix_closeall"));
1408}
1409
1410static void sh_unix_setlimits(void)
1411{
1412  struct rlimit limits;
1413
1414  SL_ENTER(_("sh_unix_setlimits"));
1415
1416  limits.rlim_cur = RLIM_INFINITY;
1417  limits.rlim_max = RLIM_INFINITY;
1418
1419#ifdef RLIMIT_CPU
1420  setrlimit (RLIMIT_CPU,     &limits);
1421#endif
1422#ifdef RLIMIT_FSIZE
1423  setrlimit (RLIMIT_FSIZE,   &limits);
1424#endif
1425#ifdef RLIMIT_DATA
1426  setrlimit (RLIMIT_DATA,    &limits);
1427#endif
1428#ifdef RLIMIT_STACK
1429  setrlimit (RLIMIT_STACK,   &limits);
1430#endif
1431#ifdef RLIMIT_RSS
1432  setrlimit (RLIMIT_RSS,     &limits);
1433#endif
1434#ifdef RLIMIT_NPROC
1435  setrlimit (RLIMIT_NPROC,   &limits);
1436#endif
1437#ifdef RLIMIT_MEMLOCK
1438  setrlimit (RLIMIT_MEMLOCK, &limits);
1439#endif
1440
1441#if !defined(SL_DEBUG)
1442  /* no core dumps
1443   */
1444  limits.rlim_cur = 0;
1445  limits.rlim_max = 0;
1446#ifdef RLIMIT_CORE
1447  setrlimit (RLIMIT_CORE,    &limits);
1448#endif
1449#else
1450#ifdef RLIMIT_CORE
1451  setrlimit (RLIMIT_CORE,    &limits);
1452#endif
1453#endif
1454
1455  limits.rlim_cur = 1024;
1456  limits.rlim_max = 1024;
1457
1458#if defined(RLIMIT_NOFILE)
1459  setrlimit (RLIMIT_NOFILE,  &limits);
1460#elif defined(RLIMIT_OFILE)
1461  setrlimit (RLIMIT_OFILE,   &limits);
1462#endif
1463
1464  SL_RET0(_("sh_unix_setlimits"));
1465}
1466
1467static void sh_unix_copyenv(void)
1468{
1469  char ** env0 = environ; 
1470  char ** env1;
1471  int   envlen = 0;
1472  size_t len;
1473
1474  SL_ENTER(_("sh_unix_copyenv"));
1475
1476  while (env0 != NULL && env0[envlen] != NULL) { 
1477    /* printf("%2d: %s\n", envlen, env0[envlen]); */
1478    ++envlen; 
1479  }
1480  ++envlen;
1481
1482  /* printf("-> %2d: slots allocated\n", envlen); */
1483  env1 = calloc(1,sizeof(char *) * envlen);      /* only once */
1484  if (env1 == NULL)
1485    {
1486      fprintf(stderr, _("%s: %d: Out of memory\n"), FIL__, __LINE__);
1487      SL_RET0(_("sh_unix_copyenv"));
1488    }
1489  env0   = environ;
1490  envlen = 0;
1491
1492  while (env0 != NULL && env0[envlen] != NULL) {
1493    len = strlen(env0[envlen]) + 1;
1494    env1[envlen] = calloc(1,len); /* only once */
1495    if (env1[envlen] == NULL)
1496      {
1497        int i;
1498        fprintf(stderr, _("%s: %d: Out of memory\n"), FIL__, __LINE__);
1499        for (i = 0; i < envlen; ++i) free(env1[len]);
1500        free(env1);
1501        SL_RET0(_("sh_unix_copyenv"));
1502      }
1503    sl_strlcpy(env1[envlen], env0[envlen], len);
1504    ++envlen;
1505  }
1506  env1[envlen] = NULL;
1507
1508  environ = env1;
1509  SL_RET0(_("sh_unix_copyenv"));
1510}
1511
1512/* delete all environment variables
1513 */
1514static void sh_unix_zeroenv(void)
1515{
1516  char * c;
1517  char ** env;
1518
1519  SL_ENTER(_("sh_unix_zeroenv"));
1520
1521  sh_unix_copyenv();
1522  env = environ;
1523
1524  while (env != NULL && *env != NULL) {
1525    c = strchr ((*env), '=');
1526#ifdef WITH_MYSQL
1527    /*
1528     * Skip the MYSQL_UNIX_PORT environment variable; MySQL may need it.
1529     */
1530    if (0 == sl_strncmp((*env), _("MYSQL_UNIX_PORT="), 16))
1531      {
1532        ++(env);
1533        continue;
1534      }
1535    if (0 == sl_strncmp((*env), _("MYSQL_TCP_PORT="), 15))
1536      {
1537        ++(env);
1538        continue;
1539      }
1540    if (0 == sl_strncmp((*env), _("MYSQL_HOME="), 11))
1541      {
1542        ++(env);
1543        continue;
1544      }
1545#endif
1546#ifdef WITH_ORACLE
1547    /*
1548     * Skip the ORACLE_HOME and TNS_ADMIN environment variables;
1549     * Oracle may need them.
1550     */
1551    if (0 == sl_strncmp((*env), _("ORACLE_HOME="), 12))
1552      {
1553        ++(env);
1554        continue;
1555      }
1556    if (0 == sl_strncmp((*env), _("TNS_ADMIN="), 10))
1557      {
1558        ++(env);
1559        continue;
1560      }
1561#endif
1562    /*
1563     * Skip the TZ environment variable.
1564     */
1565    if (0 == sl_strncmp((*env), _("TZ="), 3))
1566      {
1567        ++(env);
1568        continue;
1569      }
1570    ++(env);
1571    if (c != NULL)
1572      {
1573        ++c;
1574        while ((*c) != '\0') {
1575          (*c) = '\0';
1576          ++c;
1577        }
1578      }
1579  }
1580
1581#ifdef HAVE_TZSET
1582  tzset();
1583#endif
1584
1585  SL_RET0(_("sh_unix_zeroenv"));
1586}
1587
1588
1589static void  sh_unix_resettimer(void)
1590{
1591  struct itimerval this_timer;
1592
1593  SL_ENTER(_("sh_unix_resettimer"));
1594
1595  this_timer.it_value.tv_sec  = 0;
1596  this_timer.it_value.tv_usec = 0;
1597
1598  this_timer.it_interval.tv_sec  = 0;
1599  this_timer.it_interval.tv_usec = 0;
1600
1601  setitimer(ITIMER_REAL,    &this_timer, NULL);
1602#if !defined(SH_PROFILE)
1603  setitimer(ITIMER_VIRTUAL, &this_timer, NULL);
1604  setitimer(ITIMER_PROF,    &this_timer, NULL);
1605#endif
1606
1607  SL_RET0(_("sh_unix_resettimer"));
1608}
1609
1610static void  sh_unix_resetsignals(void)
1611{
1612  int  sig_num;
1613#ifdef NSIG
1614  int  max_sig = NSIG; 
1615#else
1616  int  max_sig = 255;
1617#endif
1618  int  test;
1619  int  status;
1620  struct sigaction act;
1621#if !defined(SH_PROFILE)
1622  struct sigaction oldact;
1623#endif
1624
1625  sigset_t set_proc;
1626
1627  SL_ENTER(_("sh_unix_resetsignals"));
1628  /*
1629   * Reset the current signal mask (inherited from parent process).
1630   */
1631
1632  sigfillset(&set_proc);
1633
1634  do {
1635    errno = 0;
1636    test  = SH_SETSIGMASK(SIG_UNBLOCK, &set_proc, NULL);
1637  } while (test < 0 && errno == EINTR);
1638
1639  /*
1640   * Reset signal handling.
1641   */
1642 
1643  act.sa_handler = SIG_DFL;         /* signal action           */
1644  sigemptyset( &act.sa_mask );      /* set an empty mask       */
1645  act.sa_flags = 0;                 /* init sa_flags           */
1646
1647  for (sig_num = 1; sig_num <= max_sig; ++sig_num) 
1648    {
1649#if !defined(SH_PROFILE)
1650      test = retry_sigaction(FIL__, __LINE__, sig_num,  &act, &oldact);
1651#else
1652      test = 0;
1653#endif
1654      if ((test == -1) && (errno != EINVAL)) 
1655        {
1656          char errbuf[SH_ERRBUF_SIZE];
1657          status = errno;
1658          sh_error_handle ((-1), FIL__, __LINE__, status, MSG_W_SIG,
1659                           sh_error_message (status, errbuf, sizeof(errbuf)), sig_num);
1660        }
1661    }
1662
1663  SL_RET0(_("sh_unix_resetsignals"));
1664}
1665
1666/* Get the local hostname (FQDN)
1667 */
1668static char * sh_tolower (char * s)
1669{
1670  char * ret = s;
1671  if (s)
1672    {
1673      for (; *s; ++s)
1674        { 
1675          *s = tolower((unsigned char) *s);
1676        }
1677    }
1678  return ret;
1679}
1680
1681
1682#include <sys/socket.h> 
1683
1684/* Required for BSD
1685 */
1686#ifdef HAVE_NETINET_IN_H
1687#include <netinet/in.h>
1688#endif
1689
1690#include <arpa/inet.h>
1691
1692const char * sh_unix_h_name (struct hostent * host_entry)
1693{
1694        char ** p;
1695        if (strchr(host_entry->h_name, '.')) {
1696                return host_entry->h_name;
1697        } else {
1698                for (p = host_entry->h_aliases; *p; ++p) {
1699                        if (strchr(*p, '.'))
1700                                return *p;
1701                }
1702        }
1703        return host_entry->h_name;
1704}
1705
1706/* uname() on FreeBSD is broken, because the 'nodename' buf is too small
1707 * to hold a valid (leftmost) domain label.
1708 */
1709#if defined(HAVE_UNAME) && !defined(HOST_IS_FREEBSD)
1710#include <sys/utsname.h>
1711void sh_unix_localhost()
1712{
1713  struct utsname   buf;
1714  int              i;
1715  unsigned int     ddot;
1716  int              len;
1717  char           * p;
1718  char             hostname[256];
1719  char             numeric[SH_IP_BUF];
1720  char           * canonical;
1721
1722
1723  SL_ENTER(_("sh_unix_localhost"));
1724
1725  (void) uname (&buf);
1726  /* flawfinder: ignore */ /* ff bug, ff sees system() */
1727  sl_strlcpy (sh.host.system,  buf.sysname, SH_MINIBUF);
1728  sl_strlcpy (sh.host.release, buf.release, SH_MINIBUF);
1729  sl_strlcpy (sh.host.machine, buf.machine, SH_MINIBUF);
1730
1731  /* Workaround for cases where nodename could be
1732   * a truncated FQDN.
1733   */
1734  if (strlen(buf.nodename) == (sizeof(buf.nodename)-1))
1735    {
1736      p = strchr(buf.nodename, '.');
1737      if (NULL != p) {
1738        *p = '\0';
1739        sl_strlcpy(hostname, buf.nodename, 256);
1740      } else {
1741#ifdef HAVE_GETHOSTNAME
1742        if (0 != gethostname(hostname, 256))
1743          {
1744            sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1745                            _("nodename returned by uname may be truncated"), 
1746                            _("sh_unix_localhost"));
1747            sl_strlcpy (hostname, buf.nodename, 256);
1748          }
1749        else
1750          {
1751            hostname[255] = '\0';
1752          }
1753#else
1754        sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1755                        _("nodename returned by uname may be truncated"), 
1756                        _("sh_unix_localhost"));
1757        sl_strlcpy(hostname, buf.nodename, 256);
1758#endif
1759      }
1760    }
1761  else
1762    {
1763      sl_strlcpy(hostname, buf.nodename, 256);
1764    }
1765
1766  canonical = sh_ipvx_canonical(hostname, numeric, sizeof(numeric));
1767
1768  if (canonical == NULL)
1769    {
1770      sl_strlcpy (sh.host.name, hostname,    SH_PATHBUF);
1771      sh_tolower (sh.host.name);
1772    }
1773  else
1774    {
1775      sl_strlcpy (sh.host.name, canonical,   SH_PATHBUF);
1776      SH_FREE(canonical);
1777    }
1778
1779  /* check whether it looks like a FQDN
1780   */
1781  len = sl_strlen(sh.host.name);
1782  ddot = 0;
1783  for (i = 0; i < len; ++i) 
1784    if (sh.host.name[i] == '.') ++ddot; 
1785
1786  if (ddot == 0)
1787    { 
1788      dlog(1, FIL__, __LINE__, 
1789           _("According to uname, your nodename is %s, but your resolver\nlibrary cannot resolve this nodename to a FQDN.\nRather, it resolves this to %s.\nFor more information, see the entry about self-resolving under\n'Most frequently' in the FAQ that you will find in the docs/ subdirectory.\n"),
1790           hostname, sh.host.name);
1791      sl_strlcpy (sh.host.name, numeric, SH_PATHBUF);
1792      SL_RET0(_("sh_unix_localhost"));
1793    } 
1794
1795  if (sh_ipvx_is_numeric(sh.host.name)) 
1796    {
1797      dlog(1, FIL__, __LINE__, 
1798           _("According to uname, your nodename is %s, but your resolver\nlibrary cannot resolve this nodename to a FQDN.\nRather, it resolves this to %s.\nFor more information, see the entry about self-resolving under\n'Most frequently' in the FAQ that you will find in the docs/ subdirectory.\n"),
1799           hostname, sh.host.name);
1800    }
1801
1802  SL_RET0(_("sh_unix_localhost"));
1803}
1804
1805#else
1806
1807/*
1808 * --FreeBSD code
1809 */
1810#if defined(HAVE_UNAME)
1811#include <sys/utsname.h>
1812#endif
1813void sh_unix_localhost()
1814{
1815#if defined(HAVE_UNAME)
1816  struct utsname   buf;
1817#endif
1818  int              i;
1819  int              ddot;
1820  int              len;
1821  char             hostname[1024];
1822  char             numeric[SH_IP_BUF];
1823  char           * canonical;
1824
1825  SL_ENTER(_("sh_unix_localhost"));
1826
1827#if defined(HAVE_UNAME)
1828  (void) uname (&buf);
1829  /* flawfinder: ignore */ /* ff bug, ff sees system() */
1830  sl_strlcpy (sh.host.system,  buf.sysname, SH_MINIBUF);
1831  sl_strlcpy (sh.host.release, buf.release, SH_MINIBUF);
1832  sl_strlcpy (sh.host.machine, buf.machine, SH_MINIBUF);
1833#endif
1834
1835  (void) gethostname (hostname, 1024);
1836  hostname[1023] = '\0';
1837
1838  canonical = sh_ipvx_canonical(hostname, numeric, sizeof(numeric));
1839
1840  if (canonical == NULL)
1841    {
1842      sl_strlcpy (sh.host.name, hostname, SH_PATHBUF);
1843      sh_tolower (sh.host.name);
1844    }
1845  else
1846    {
1847      sl_strlcpy (sh.host.name, canonical,   SH_PATHBUF);
1848      SH_FREE(canonical);
1849    }
1850
1851  /* check whether it looks like a FQDN
1852   */
1853  len = sl_strlen(sh.host.name);
1854  ddot = 0;
1855  for (i = 0; i < len; ++i) 
1856    if (sh.host.name[i] == '.') ++ddot; 
1857  if (ddot == 0) 
1858    {
1859      dlog(1, FIL__, __LINE__, 
1860           _("According to uname, your nodename is %s, but your resolver\nlibrary cannot resolve this nodename to a FQDN.\nRather, it resolves this to %s.\nFor more information, see the entry about self-resolving under\n'Most frequently' in the FAQ that you will find in the docs/ subdirectory.\n"),
1861           hostname, sh.host.name);
1862      sl_strlcpy (sh.host.name, numeric, SH_PATHBUF);
1863      SL_RET0(_("sh_unix_localhost"));
1864    }
1865
1866  if (sh_ipvx_is_numeric(sh.host.name)) 
1867    {
1868      dlog(1, FIL__, __LINE__, 
1869           _("According to uname, your nodename is %s, but your resolver\nlibrary cannot resolve this nodename to a FQDN.\nRather, it resolves this to %s.\nFor more information, see the entry about self-resolving under\n'Most frequently' in the FAQ that you will find in the docs/ subdirectory.\n"),
1870           hostname, sh.host.name);
1871    }
1872
1873  SL_RET0(_("sh_unix_localhost"));
1874}
1875#endif
1876
1877
1878void sh_unix_memlock()
1879{
1880  SL_ENTER(_("sh_unix_memlock"));
1881
1882  /* do this before dropping privileges
1883   */
1884#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
1885  if (skey->mlock_failed == S_FALSE)
1886    {
1887      if ( (-1) == sh_unix_mlock( FIL__, __LINE__, 
1888                                  (char *) skey, sizeof (sh_key_t)) ) 
1889        {
1890          SH_MUTEX_LOCK_UNSAFE(mutex_skey);
1891          skey->mlock_failed = S_TRUE;
1892          SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
1893        }
1894    }
1895#else
1896  if (skey->mlock_failed == S_FALSE)
1897    {
1898      SH_MUTEX_LOCK_UNSAFE(mutex_skey);
1899      skey->mlock_failed = S_TRUE;
1900      SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
1901    }
1902#endif
1903
1904  SL_RET0(_("sh_unix_memlock"));
1905}
1906
1907#ifdef SH_WITH_SERVER
1908char * chroot_dir = NULL;
1909
1910int sh_unix_set_chroot(const char * str)
1911{
1912  size_t len;
1913  static int block = 0;
1914
1915  if (block == 1)
1916    return 0;
1917
1918  if (str && *str == '/')
1919    {
1920      len = strlen(str) + 1;
1921      chroot_dir = calloc(1,strlen(str) + 1);  /* only once */
1922      if (!chroot_dir)
1923        {
1924          fprintf(stderr, _("%s: %d: Out of memory\n"), FIL__, __LINE__);
1925          return 1;
1926        }
1927      sl_strlcpy(chroot_dir, str, len);
1928      block = 1;
1929      return 0;
1930    }
1931  return 1;
1932}
1933
1934int sh_unix_chroot(void)
1935{
1936  int status;
1937
1938  if (chroot_dir != NULL)
1939    {
1940      status = retry_aud_chdir(FIL__, __LINE__, chroot_dir);
1941      if ( (-1) == status ) 
1942        {
1943          char errbuf[SH_ERRBUF_SIZE];
1944          status = errno;
1945          sh_error_handle ((-1), FIL__, __LINE__, status, MSG_W_CHDIR,
1946                           sh_error_message (status, errbuf, sizeof(errbuf)), chroot_dir);
1947          aud_exit(FIL__, __LINE__, EXIT_FAILURE);
1948        }
1949      /* flawfinder: ignore */
1950      return (chroot(chroot_dir));
1951    }
1952  return 0;
1953}
1954/* #ifdef SH_WITH_SERVER */
1955#else
1956int sh_unix_chroot(void) { return 0; }
1957#endif
1958
1959/* daemon mode
1960 */
1961static int block_setdeamon = 0;
1962
1963int sh_unix_setdeamon(const char * dummy)
1964{
1965  int    res = 0;
1966
1967  SL_ENTER(_("sh_unix_setdeamon"));
1968
1969  if (block_setdeamon != 0)
1970    SL_RETURN((0),_("sh_unix_setdeamon"));
1971
1972  if (dummy == NULL)
1973    sh.flag.isdaemon = S_TRUE;
1974  else 
1975    res = sh_util_flagval (dummy, &sh.flag.isdaemon);
1976
1977  if (sh.flag.opts == S_TRUE) 
1978    block_setdeamon = 1;
1979           
1980  SL_RETURN(res, _("sh_unix_setdeamon"));
1981}
1982#if defined(HAVE_LIBPRELUDE)
1983#include "sh_prelude.h"
1984#endif
1985
1986int sh_unix_setnodeamon(const char * dummy)
1987{
1988  int    res = 0;
1989 
1990  SL_ENTER(_("sh_unix_setnodeamon"));
1991
1992  if (block_setdeamon != 0)
1993    SL_RETURN((0),_("sh_unix_setmodeamon"));
1994
1995  if (dummy == NULL)
1996    sh.flag.isdaemon = S_FALSE;
1997  else 
1998    res = sh_util_flagval (dummy, &sh.flag.isdaemon);
1999
2000  if (sh.flag.opts == S_TRUE) 
2001    block_setdeamon = 1;
2002           
2003  SL_RETURN(res, _("sh_unix_setnodeamon"));
2004}
2005
2006int sh_unix_init(int goDaemon)
2007{
2008  int    status;
2009  uid_t  uid;
2010  pid_t  oldpid = getpid();
2011#if defined(SH_WITH_SERVER)
2012  extern int sh_socket_open_int (void);
2013#endif
2014  char errbuf[SH_ERRBUF_SIZE];
2015
2016  extern void sh_kill_sub();
2017
2018  SL_ENTER(_("sh_unix_init"));
2019
2020  /* fork twice, exit the parent process
2021   */
2022  if (goDaemon == 1) {
2023   
2024    switch (aud_fork(FIL__, __LINE__)) {
2025    case 0:  break;                             /* child process continues */
2026    case -1: SL_RETURN((-1),_("sh_unix_init")); /* error                   */
2027    default:                                    /* parent process exits    */
2028      sh_kill_sub(); 
2029      aud__exit(FIL__, __LINE__, 0);
2030    }
2031
2032    /* Child processes do not inherit page locks across a fork.
2033     * Error in next fork would return in this (?) thread of execution.
2034     */
2035    sh_unix_memlock();
2036
2037    setsid();            /* should not fail         */
2038    sh.pid = (UINT64) getpid();
2039
2040    switch (aud_fork(FIL__, __LINE__)) {
2041    case 0:  break;                             /* child process continues */
2042    case -1: SL_RETURN((-1),_("sh_unix_init")); /* error                   */
2043    default:                                    /* parent process exits    */
2044      sh_kill_sub(); 
2045      aud__exit(FIL__, __LINE__, 0);
2046    }
2047
2048    /* Child processes do not inherit page locks across a fork.
2049     */
2050    sh_unix_memlock();
2051    sh.pid = (UINT64) getpid();
2052
2053  } else {
2054    setsid();            /* should not fail         */
2055  } 
2056
2057  /* set working directory   
2058   */
2059#ifdef SH_PROFILE
2060  status = 0;
2061#else
2062  status = retry_aud_chdir(FIL__, __LINE__, "/");
2063#endif
2064  if ( (-1) == status ) 
2065    {
2066      status = errno;
2067      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_W_CHDIR,
2068                       sh_error_message (status, errbuf, sizeof(errbuf)), "/");
2069      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
2070    }
2071
2072  /* reset timers
2073   */
2074  sh_unix_resettimer();
2075
2076  /* signal handlers
2077   */
2078  sh_unix_resetsignals();
2079#if defined(SCREW_IT_UP)
2080  sh_sigtrap_prepare();
2081#endif
2082  sh_unix_siginstall  (goDaemon);
2083
2084  /* set file creation mask
2085   */
2086  (void) umask (0); /* should not fail */
2087
2088  /* set resource limits to maximum, and
2089   * core dump size to zero
2090   */
2091  sh_unix_setlimits();
2092
2093  /* zero out the environment (like PATH='\0') 
2094   */
2095  sh_unix_zeroenv();
2096
2097  if (goDaemon == 1)
2098    {
2099      /* Close first tree file descriptors
2100       */ 
2101      sl_close_fd (FIL__, __LINE__, 0);  /* if running as daemon */
2102      sl_close_fd (FIL__, __LINE__, 1);  /* if running as daemon */
2103      sl_close_fd (FIL__, __LINE__, 2);  /* if running as daemon */
2104
2105      /* Enable full error logging
2106       */
2107      sh_error_only_stderr (S_FALSE);
2108
2109      /* open first three streams to /dev/null
2110       */
2111      status = aud_open(FIL__, __LINE__, SL_NOPRIV, _("/dev/null"), O_RDWR, 0);
2112      if (status < 0)
2113        {
2114          status = errno;
2115          sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, 
2116                          sh_error_message(status, errbuf, sizeof(errbuf)), _("open"));
2117          aud_exit(FIL__, __LINE__, EXIT_FAILURE);
2118        }
2119
2120      status = retry_aud_dup(FIL__, __LINE__, 0); 
2121      if (status >= 0)
2122        retry_aud_dup(FIL__, __LINE__, 0);
2123
2124      if (status < 0)
2125        {
2126          status = errno;
2127          sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, 
2128                          sh_error_message(status, errbuf, sizeof(errbuf)), _("dup"));
2129          aud_exit(FIL__, __LINE__, EXIT_FAILURE);
2130        }
2131
2132      sh_error_enable_unsafe (S_TRUE);
2133#if defined(HAVE_LIBPRELUDE)
2134      sh_prelude_reset ();
2135#endif
2136
2137      /* --- wait until parent has exited ---
2138       */
2139      while (1 == 1)
2140        {
2141          errno = 0;
2142          if (0 > aud_kill (FIL__, __LINE__, oldpid, 0) && errno == ESRCH)
2143            {
2144              break;
2145            }
2146          retry_msleep(0, 1);
2147        }
2148
2149      /* write PID file
2150       */
2151      status = sh_unix_write_pid_file();
2152      if (status < 0)
2153        {
2154          sl_get_euid(&uid);
2155          sh_error_handle ((-1), FIL__, __LINE__, status, MSG_PIDFILE,
2156                           (long) uid, sh.srvlog.alt);
2157          aud_exit(FIL__, __LINE__, EXIT_FAILURE);
2158        }
2159#if defined(SH_WITH_SERVER)
2160      sh_socket_open_int ();
2161#endif
2162    }
2163  else
2164    {
2165      sh_error_enable_unsafe (S_TRUE);
2166#if defined(HAVE_LIBPRELUDE)
2167      sh_prelude_reset ();
2168#endif
2169#if defined(SH_WITH_SERVER)
2170      sh_socket_open_int ();
2171#endif
2172    }
2173
2174  /* chroot (this is a no-op if no chroot dir is specified
2175   */
2176  status = sh_unix_chroot();
2177  if (status < 0)
2178    {
2179      status = errno;
2180      sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, 
2181                          sh_error_message(status, errbuf, sizeof(errbuf)), _("chroot"));
2182      aud_exit(FIL__, __LINE__, EXIT_FAILURE);
2183    }
2184
2185  /* drop capabilities
2186   */
2187  sl_drop_cap();
2188
2189  SL_RETURN((0),_("sh_unix_init"));
2190}
2191
2192/* --- run a command, securely --- */
2193
2194int sh_unix_run_command (const char * str)
2195{
2196  pid_t  pid;
2197  char * arg[4];
2198  char * env[5];
2199  char * path = sh_util_strdup(_("/bin/sh"));
2200
2201  int  status = -1;
2202
2203  arg[0] = sh_util_strdup(_("/bin/sh"));
2204  arg[1] = sh_util_strdup(_("-c"));
2205  arg[2] = sh_util_strdup(str);
2206  arg[3] = NULL;
2207
2208  env[0] = sh_util_strdup(_("PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/ucb"));
2209  env[1] = sh_util_strdup(_("SHELL=/bin/sh"));
2210  env[2] = sh_util_strdup(_("IFS= \t\n"));
2211  if (getenv("TZ")) {                         /* flawfinder: ignore */
2212    char * tz = sh_util_strdup(getenv("TZ")); /* flawfinder: ignore */
2213    size_t tzlen = strlen(tz);
2214    if (S_TRUE == sl_ok_adds (4, tzlen)) {
2215        env[3] = SH_ALLOC(4+tzlen);
2216        sl_strlcpy(env[3], "TZ=", 4);
2217        sl_strlcat(env[3], tz   , 4+tzlen);
2218    } else {
2219      env[3] = NULL;
2220    }
2221  } else {
2222    env[3] = NULL;
2223  }
2224  env[4] = NULL;
2225
2226  pid = fork();
2227
2228  if (pid == (pid_t)(-1))
2229    {
2230      return -1;
2231    }
2232
2233  else if (pid == 0) /* child */
2234    {
2235      memset(skey, 0, sizeof(sh_key_t));
2236      (void) umask(S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
2237      sh_unix_closeall (3, -1, S_TRUE); /* in child process */
2238      execve(path, arg, env);
2239      _exit(EXIT_FAILURE);
2240    }
2241
2242  else /* parent */
2243    {
2244      int r;
2245
2246      while((r = waitpid(pid, &status, WUNTRACED)) != pid && r != -1) ;
2247
2248#if !defined(USE_UNO)
2249      if (r == -1 || !WIFEXITED(status)) 
2250        {
2251          status = -1;
2252        }
2253      else
2254        {
2255          status = WEXITSTATUS(status);
2256        }
2257#endif
2258     }
2259
2260  return status;
2261}
2262
2263/********************************************************
2264 *
2265 *  TIME
2266 *
2267 ********************************************************/
2268
2269/* Figure out the time offset of the current timezone
2270 * in a portable way.
2271 */
2272char * t_zone(const time_t * xx)
2273{
2274  struct tm   aa;
2275  struct tm   bb;
2276
2277  struct tm * aptr;
2278  struct tm * bptr;
2279
2280  int  sign =  0;
2281  int  diff =  0;
2282  int  hh, mm;
2283  static char tz[64];
2284
2285  SL_ENTER(_("t_zone"));
2286
2287#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GMTIME_R)
2288  aptr = gmtime_r (xx, &aa);
2289#else
2290  aptr = gmtime(xx);
2291  if (aptr)
2292    memcpy (&aa, aptr, sizeof(struct tm));
2293#endif
2294
2295#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
2296  bptr = localtime_r (xx, &bb);
2297#else
2298  bptr = localtime(xx);
2299  if (bptr) 
2300    memcpy (&bb, bptr, sizeof(struct tm));
2301#endif
2302
2303  if (bptr && aptr)
2304    {
2305      /* Check for datum wrap-around.
2306       */
2307      if      (aa.tm_year < bb.tm_year)
2308        sign = (-1);
2309      else if (aa.tm_mon  < bb.tm_mon)
2310        sign = (-1);
2311      else if (aa.tm_mday < bb.tm_mday)
2312        sign = (-1);
2313      else if (bb.tm_year < aa.tm_year)
2314        sign = ( 1);
2315      else if (bb.tm_mon  < aa.tm_mon)
2316        sign = ( 1);
2317      else if (bb.tm_mday < aa.tm_mday)
2318        sign = ( 1);
2319     
2320      diff = aa.tm_hour * 60 + aa.tm_min;
2321      diff = (bb.tm_hour * 60 + bb.tm_min) - diff;
2322      diff = diff - (sign * 24 * 60);   /* datum wrap-around correction */
2323      hh = diff / 60;
2324      mm = diff - (hh * 60);
2325      sprintf (tz, _("%+03d%02d"), hh, mm);                /* known to fit  */
2326    }
2327  else
2328    {
2329      sprintf (tz, _("%+03d%02d"), 0, 0);
2330    }
2331  SL_RETURN(tz, _("t_zone"));
2332}
2333
2334unsigned long sh_unix_longtime ()
2335{
2336  return ((unsigned long)time(NULL));
2337} 
2338
2339#ifdef HAVE_GETTIMEOFDAY
2340unsigned long sh_unix_notime ()
2341{
2342  struct timeval  tv;
2343
2344  gettimeofday (&tv, NULL);
2345
2346  return ((unsigned long)(tv.tv_sec + tv.tv_usec * 10835 + getpid() + getppid()));
2347 
2348}
2349#endif
2350
2351static int count_dev_time = 0;
2352
2353void reset_count_dev_time(void)
2354{
2355  count_dev_time = 0;
2356  return;
2357}
2358
2359int sh_unix_settimeserver (const char * address)
2360{
2361
2362  SL_ENTER(_("sh_unix_settimeserver"));
2363
2364  if (address != NULL && count_dev_time < 2 
2365      && sl_strlen(address) < SH_PATHBUF) 
2366    {
2367      if (count_dev_time == 0)
2368        sl_strlcpy (sh.srvtime.name, address, SH_PATHBUF);
2369      else
2370        sl_strlcpy (sh.srvtime.alt,  address, SH_PATHBUF);
2371
2372      ++count_dev_time;
2373      SL_RETURN((0), _("sh_unix_settimeserver"));
2374    }
2375  SL_RETURN((-1), _("sh_unix_settimeserver"));
2376}
2377
2378
2379#ifdef HAVE_NTIME
2380#define UNIXEPOCH 2208988800UL  /* difference between Unix time and net time
2381                                 * The UNIX EPOCH starts in 1970.
2382                                 */
2383#include <sys/socket.h>
2384#include <netinet/in.h>
2385#include <arpa/inet.h>
2386#include <netdb.h>
2387#include <ctype.h>
2388#endif
2389
2390/* Timeserver service.               */
2391/* define is missing on HP-UX 10.20  */
2392#ifndef IPPORT_TIMESERVER
2393#define IPPORT_TIMESERVER 37
2394#endif
2395
2396char * sh_unix_time (time_t thetime, char * buffer, size_t len)
2397{
2398
2399  int           status;
2400  char          AsciiTime[81];                       /* local time   */
2401  time_t        time_now;
2402  struct tm   * time_ptr;
2403#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
2404  struct tm     time_tm;
2405#endif
2406#ifdef SH_USE_XML
2407  static char   deftime[] = N_("0000-00-00T00:00:00"); /* default time */
2408#else
2409  static char   deftime[] = N_("[0000-00-00T00:00:00]"); /* default time */
2410#endif
2411
2412#ifdef HAVE_NTIME
2413  int    fd;                    /* network file descriptor                  */
2414  u_char net_time[4];           /* remote time in network format            */
2415  static int failerr = 0;       /* no net time                              */
2416  int    fail = 0;              /* no net time                              */
2417  int    errflag;
2418  char   errmsg[256];
2419  char   error_call[SH_MINIBUF];
2420  int    error_num;
2421#endif
2422 
2423  SL_ENTER(_("sh_unix_time"));
2424
2425#ifdef HAVE_NTIME
2426  if (thetime == 0) 
2427    {
2428      if (sh.srvtime.name[0] == '\0') 
2429        {
2430          fail = 1;
2431          (void) time (&time_now);
2432        } 
2433      else /* have a timeserver address */
2434        { 
2435          /* don't call timeserver more than once per second */
2436          static time_t  time_old   = 0;
2437          time_t         time_new;
2438          static time_t  time_saved = 0;
2439          (void) time (&time_new);
2440          if ((time_new == time_old) && (time_saved != 0))
2441            {
2442              time_now = time_saved;
2443              goto end;
2444            }
2445          time_old = time_new;
2446
2447
2448          fd = connect_port_2 (sh.srvtime.name, sh.srvtime.alt, 
2449                               IPPORT_TIMESERVER, 
2450                               error_call, &error_num, errmsg, sizeof(errmsg));
2451          if (fd >= 0)
2452            {
2453              if (4 != read_port (fd, (char *) net_time, 4, &errflag, 2))
2454                {
2455                  fail = 1;
2456                  sh_error_handle ((-1), FIL__, __LINE__, errflag, 
2457                                   MSG_E_NLOST, 
2458                                   _("time"), sh.srvtime.name);
2459                }
2460              sl_close_fd(FIL__, __LINE__, fd);
2461            }
2462          else
2463            {
2464              sh_error_handle ((-1), FIL__, __LINE__, error_num, 
2465                               MSG_E_NET, errmsg, error_call,
2466                               _("time"), sh.srvtime.name);
2467              fail = 1;
2468            }
2469         
2470          if (fail == 0) 
2471            { 
2472              unsigned long   ltmp;
2473              UINT32          ttmp;
2474              memcpy(&ttmp, net_time, sizeof(UINT32)); ltmp = ttmp;
2475              time_now = ntohl(ltmp) - UNIXEPOCH;
2476              time_saved = time_now;
2477
2478              if (failerr == 1) {
2479                failerr = 0;
2480                sh_error_handle ((-1), FIL__, __LINE__, 0, 
2481                                 MSG_E_NEST, 
2482                                 _("time"), sh.srvtime.name);
2483              } 
2484            }
2485          else
2486            {
2487              (void) time (&time_now);
2488              time_saved = 0;
2489
2490              if (failerr == 0)
2491                {
2492                  failerr = 1;
2493                  sh_error_handle ((-1), FIL__, __LINE__, errflag, 
2494                                   MSG_SRV_FAIL, 
2495                                   _("time"), sh.srvtime.name);
2496                }
2497            }
2498        end:
2499          ; /* 'label at end of compound statement' */
2500        }
2501    }
2502  else 
2503    {
2504      time_now = thetime;
2505    }
2506
2507  /* #ifdef HAVE_NTIME */
2508#else
2509
2510  if (thetime == 0) 
2511    {
2512      (void) time (&time_now);
2513    } 
2514  else 
2515    {
2516      time_now = thetime;
2517    }
2518
2519  /* #ifdef HAVE_NTIME */
2520#endif
2521
2522  if (time_now == (-1) )
2523    {
2524      sl_strlcpy(buffer, _(deftime), len);
2525      SL_RETURN(buffer, _("sh_unix_time"));
2526    }
2527  else
2528    {
2529#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
2530      time_ptr   = localtime_r (&time_now, &time_tm);
2531#else
2532      time_ptr   = localtime (&time_now);
2533#endif
2534    }
2535  if (time_ptr != NULL) 
2536    {
2537      status = strftime (AsciiTime, sizeof(AsciiTime),
2538#ifdef SH_USE_XML
2539                         _("%Y-%m-%dT%H:%M:%S%%s"),
2540#else
2541                         _("[%Y-%m-%dT%H:%M:%S%%s]"),
2542#endif
2543                         time_ptr);
2544
2545      sl_snprintf(buffer, len, AsciiTime, t_zone(&time_now));
2546
2547      if ( (status == 0) || (status == sizeof(AsciiTime)) )
2548        {
2549          sl_strlcpy(buffer, _(deftime), len);
2550          SL_RETURN( buffer, _("sh_unix_time"));
2551        }
2552      else
2553        {
2554          SL_RETURN(buffer, _("sh_unix_time"));
2555        }
2556    }
2557
2558  /* last resort
2559   */
2560  sl_strlcpy(buffer, _(deftime), len);
2561  SL_RETURN( buffer, _("sh_unix_time"));
2562}
2563
2564static int sh_unix_use_localtime = S_FALSE;
2565
2566/* whether to use localtime for file timestamps in logs
2567 */
2568int sh_unix_uselocaltime (const char * c)
2569{
2570  int i;
2571  SL_ENTER(_("sh_unix_uselocaltime"));
2572  i = sh_util_flagval(c, &(sh_unix_use_localtime));
2573
2574  SL_RETURN(i, _("sh_unix_uselocaltime"));
2575}
2576   
2577char * sh_unix_gmttime (time_t thetime, char * buffer, size_t len)
2578{
2579
2580  int           status;
2581
2582  struct tm   * time_ptr;
2583#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS)
2584  struct tm     time_tm;
2585#endif
2586  char   AsciiTime[81];                       /* GMT time   */
2587#ifdef SH_USE_XML
2588  static char   deftime[] = N_("0000-00-00T00:00:00"); /* default time */
2589#else
2590  static char   deftime[] = N_("[0000-00-00T00:00:00]"); /* default time */
2591#endif
2592
2593  SL_ENTER(_("sh_unix_gmttime"));
2594
2595  if (sh_unix_use_localtime == S_FALSE)
2596    {
2597#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GMTIME_R)
2598      time_ptr   = gmtime_r (&thetime, &time_tm);
2599#else
2600      time_ptr   = gmtime (&thetime);
2601#endif
2602    }
2603  else
2604    {
2605#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
2606      time_ptr   = localtime_r (&thetime, &time_tm);
2607#else
2608      time_ptr   = localtime (&thetime);
2609#endif
2610    }
2611  if (time_ptr != NULL) 
2612    {
2613      status = strftime (AsciiTime, 80,
2614#ifdef SH_USE_XML
2615                         _("%Y-%m-%dT%H:%M:%S"),
2616#else
2617                         _("[%Y-%m-%dT%H:%M:%S]"),
2618#endif
2619                         time_ptr);
2620
2621      if ( (status == 0) || (status == 80) )
2622        sl_strlcpy(buffer, _(deftime), len);
2623      else
2624        sl_strlcpy(buffer, AsciiTime, len);
2625      SL_RETURN( buffer, _("sh_unix_gmttime"));
2626    }
2627
2628  /* last resort
2629   */
2630  sl_strlcpy(buffer, _(deftime), len);
2631  SL_RETURN( buffer, _("sh_unix_gmttime"));
2632}
2633
2634
2635char *  sh_unix_getUIDdir (int level, uid_t uid, char * out, size_t len)
2636{
2637  struct passwd * tempres;
2638  int    status = 0;
2639
2640#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R)
2641  struct passwd pwd;
2642  char   * buffer;
2643#endif
2644  char errbuf[SH_ERRBUF_SIZE];
2645
2646  SL_ENTER(_("sh_unix_getUIDdir"));
2647
2648#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R)
2649  buffer = SH_ALLOC(SH_PWBUF_SIZE);
2650  sh_getpwuid_r(uid, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
2651#else
2652  errno = 0;
2653  tempres = sh_getpwuid(uid);
2654  status = errno;
2655#endif
2656
2657  if (tempres == NULL) {
2658    sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL,
2659                     sh_error_message(status, errbuf, sizeof(errbuf)),
2660                     _("getpwuid"), (long) uid, _("completely missing"));
2661#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
2662    SH_FREE(buffer);
2663#endif
2664    SL_RETURN( NULL, _("sh_unix_getUIDdir"));
2665  }
2666
2667  if (tempres->pw_dir != NULL) {
2668    sl_strlcpy(out, tempres->pw_dir, len);
2669#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
2670    SH_FREE(buffer);
2671#endif
2672    SL_RETURN( out, _("sh_unix_getUIDdir"));
2673  } else {
2674    sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL,
2675                     sh_error_message(status, errbuf, sizeof(errbuf)),
2676                     _("getpwuid"), (long) uid, _("pw_dir"));
2677#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
2678    SH_FREE(buffer);
2679#endif
2680    SL_RETURN( NULL, _("sh_unix_getUIDdir"));
2681  }
2682}
2683
2684/* ------------------- Caching ----------------*/
2685#include "zAVLTree.h"
2686
2687#define CACHE_GID 0
2688#define CACHE_UID 1
2689
2690struct user_id {
2691  char  * name;
2692  uid_t   id;
2693  struct user_id * next;
2694};
2695
2696static struct user_id  * uid_list = NULL;
2697static struct user_id  * gid_list = NULL;
2698
2699SH_MUTEX_STATIC(mutex_cache, PTHREAD_MUTEX_INITIALIZER);
2700
2701static void sh_userid_free(struct user_id * item)
2702{
2703  while (item)
2704    {
2705      struct user_id * user = item;
2706      item = item->next;
2707
2708      SH_FREE(user->name);
2709      SH_FREE(user);
2710    }
2711  return;
2712}
2713
2714void sh_userid_destroy ()
2715{
2716  struct user_id * tmp_uid;
2717  struct user_id * tmp_gid;
2718
2719  SH_MUTEX_LOCK_UNSAFE(mutex_cache);
2720  tmp_gid  = gid_list;
2721  gid_list = NULL;
2722  tmp_uid  = uid_list;
2723  uid_list = NULL;
2724  SH_MUTEX_UNLOCK_UNSAFE(mutex_cache);
2725
2726  sh_userid_free(tmp_uid);
2727  sh_userid_free(tmp_gid);
2728  return;
2729}
2730
2731static void sh_userid_additem(struct user_id * list, struct user_id * item)
2732{
2733  if (list)
2734    {
2735      while (list && list->next)
2736        list = list->next;
2737      list->next = item;
2738    }
2739  return;
2740}
2741
2742static void sh_userid_add(uid_t id, char * username, int which)
2743{
2744  size_t len;
2745  struct user_id * user = SH_ALLOC(sizeof(struct user_id));
2746
2747  if (username)
2748    len  = strlen(username) + 1;
2749  else
2750    len = 1;
2751
2752  user->name = SH_ALLOC(len);
2753  user->id   = id;
2754  if (username)
2755    sl_strlcpy(user->name, username, len);
2756  else
2757    user->name[0] = '\0';
2758  user->next = NULL;
2759
2760  SH_MUTEX_LOCK(mutex_cache);
2761  if (which == CACHE_UID)
2762    {
2763      if (!uid_list)
2764        uid_list = user;
2765      else
2766        sh_userid_additem(uid_list, user);
2767    }
2768  else
2769    {
2770      if (!gid_list)
2771        gid_list = user;
2772      else
2773        sh_userid_additem(gid_list, user);
2774    }
2775  SH_MUTEX_UNLOCK(mutex_cache);
2776
2777  return;
2778}
2779
2780static char * sh_userid_search(struct user_id * list, uid_t id)
2781{
2782  while (list)
2783    {
2784      if (list->id == id)
2785        return list->name;
2786      list = list->next;
2787    }
2788  return NULL;
2789}
2790
2791static char * sh_userid_get (uid_t id, int which, char * out, size_t len)
2792{
2793  char * user = NULL;
2794
2795  SH_MUTEX_LOCK_UNSAFE(mutex_cache);
2796  if (which == CACHE_UID)
2797    user = sh_userid_search(uid_list, id);
2798  else
2799    user = sh_userid_search(gid_list, id);
2800  if (user)
2801    {
2802      sl_strlcpy(out, user, len);
2803      user = out;
2804    }
2805  SH_MUTEX_UNLOCK_UNSAFE(mutex_cache);
2806
2807  return user;
2808}
2809
2810/* --------- end caching code --------- */
2811 
2812char *  sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len)
2813{
2814  struct passwd * tempres;
2815#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R)
2816  struct passwd pwd;
2817  char   * buffer;
2818#endif
2819  int             status = 0;
2820  char errbuf[SH_ERRBUF_SIZE];
2821  char * tmp;
2822
2823  SL_ENTER(_("sh_unix_getUIDname"));
2824
2825  tmp = sh_userid_get(uid, CACHE_UID, out, len);
2826
2827  if (tmp)
2828    {
2829      if (tmp[0] != '\0')
2830        {
2831          SL_RETURN( out, _("sh_unix_getUIDname"));
2832        }
2833      else
2834        {
2835          SL_RETURN( NULL, _("sh_unix_getUIDname"));
2836        }
2837    }
2838
2839#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R)
2840  buffer = SH_ALLOC(SH_PWBUF_SIZE);
2841  sh_getpwuid_r(uid, &pwd, buffer, SH_PWBUF_SIZE, &tempres);
2842#else
2843  errno = 0;
2844  tempres = sh_getpwuid(uid);
2845  status = errno;
2846#endif
2847 
2848  if (tempres == NULL) 
2849    {
2850      sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL,
2851                       sh_error_message(status, errbuf, sizeof(errbuf)),
2852                       _("getpwuid"), (long) uid, _("completely missing"));
2853#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
2854      SH_FREE(buffer);
2855#endif
2856      sh_userid_add(uid, NULL, CACHE_UID);
2857      SL_RETURN( NULL, _("sh_unix_getUIDname"));
2858    }
2859
2860
2861  if (tempres->pw_name != NULL) 
2862    {
2863
2864      sl_strlcpy(out, tempres->pw_name, len);
2865      sh_userid_add(uid, out, CACHE_UID);
2866     
2867#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
2868      SH_FREE(buffer);
2869#endif
2870
2871      SL_RETURN( out, _("sh_unix_getUIDname"));
2872    } 
2873  else 
2874    {
2875      sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL,
2876                       sh_error_message(status, errbuf, sizeof(errbuf)),
2877                       _("getpwuid"), (long) uid, _("pw_user"));
2878#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
2879      SH_FREE(buffer);
2880#endif
2881      SL_RETURN( NULL, _("sh_unix_getUIDname"));
2882    }
2883  /* notreached */
2884}
2885
2886char *  sh_unix_getGIDname (int level, gid_t gid, char * out, size_t len)
2887{
2888  struct group  * tempres;
2889  int             status = 0;
2890
2891#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
2892  struct group    grp;
2893  char          * buffer;
2894#endif
2895  char errbuf[SH_ERRBUF_SIZE];
2896  char * tmp;
2897 
2898  SL_ENTER(_("sh_unix_getGIDname"));
2899
2900  tmp = sh_userid_get((uid_t)gid, CACHE_GID, out, len);
2901
2902  if (tmp)
2903    {
2904      if (tmp[0] != '\0')
2905        {
2906          SL_RETURN( out, _("sh_unix_getGIDname"));
2907        }
2908      else
2909        {
2910          SL_RETURN( NULL, _("sh_unix_getGIDname"));
2911        }
2912    }
2913
2914#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
2915  buffer = SH_ALLOC(SH_GRBUF_SIZE);
2916  status = sh_getgrgid_r(gid, &grp, buffer, SH_GRBUF_SIZE, &tempres);
2917#else
2918  errno = 0;
2919  tempres = sh_getgrgid(gid);
2920  status = errno;
2921#endif
2922
2923  if (status == ERANGE) 
2924    {
2925      static int seen = 0;
2926
2927      if (seen == 0)
2928        {
2929          sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_GRNULL,
2930                           sh_error_message(status, errbuf, sizeof(errbuf)),
2931                           _("getgrgid"), (long) gid, _("line too long in group entry"));
2932          ++seen;
2933        }
2934     
2935#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
2936      SH_FREE(buffer);
2937#endif
2938
2939      sh_userid_add(gid, NULL, CACHE_GID);
2940      SL_RETURN( NULL, _("sh_unix_getGIDname"));
2941    }
2942
2943  if (tempres == NULL) 
2944    {
2945      sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_GRNULL,
2946                       sh_error_message(status, errbuf, sizeof(errbuf)),
2947                       _("getgrgid"), (long) gid, _("completely missing"));
2948     
2949#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
2950      SH_FREE(buffer);
2951#endif
2952
2953      sh_userid_add(gid, NULL, CACHE_GID);
2954      SL_RETURN( NULL, _("sh_unix_getGIDname"));
2955    }
2956
2957  if (tempres->gr_name != NULL) 
2958    {
2959
2960      sl_strlcpy(out, tempres->gr_name, len);
2961      sh_userid_add((uid_t)gid, out, CACHE_GID);
2962     
2963#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
2964      SH_FREE(buffer);
2965#endif
2966
2967      SL_RETURN( out, _("sh_unix_getGIDname"));
2968    } 
2969  else 
2970    {
2971      sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_GRNULL,
2972                       sh_error_message(status, errbuf, sizeof(errbuf)),
2973                       _("getgrgid"), (long) gid, _("gr_name"));
2974
2975#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R)
2976      SH_FREE(buffer);
2977#endif
2978
2979      SL_RETURN( NULL, _("sh_unix_getGIDname"));
2980    }
2981  /* notreached */
2982}
2983
2984int sh_unix_getUser ()
2985{
2986  char          * p;
2987  uid_t  seuid, sruid;
2988  char   user[USER_MAX];
2989  char   dir[SH_PATHBUF];
2990
2991  SL_ENTER(_("sh_unix_getUser"));
2992
2993  seuid =  geteuid();
2994
2995  sh.effective.uid = seuid;
2996
2997  p = sh_unix_getUIDdir (SH_ERR_ERR, seuid, dir, sizeof(dir));
2998
2999  if (p == NULL)
3000    SL_RETURN((-1), _("sh_unix_getUser"));
3001  else
3002    {
3003      if (sl_strlen(p) >= SH_PATHBUF) {
3004        sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_PWLONG,
3005                         _("getpwuid"), (long) seuid, _("pw_home"));
3006        SL_RETURN((-1), _("sh_unix_getUser"));
3007      } else {
3008        sl_strlcpy ( sh.effective.home, p, SH_PATHBUF);
3009      }
3010    }
3011
3012  sruid = getuid();
3013
3014  sh.real.uid = sruid;
3015
3016  p = sh_unix_getUIDname (SH_ERR_ERR, sruid, user, sizeof(user));
3017  if (p == NULL)
3018    SL_RETURN((-1), _("sh_unix_getUser"));
3019  else
3020    {
3021      if (sl_strlen(p) >= USER_MAX) {
3022        sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_PWLONG,
3023                         _("getpwuid"), (long) sruid, _("pw_user"));
3024        SL_RETURN((-1), _("sh_unix_getUser"));
3025      } else {
3026        sl_strlcpy ( sh.real.user, p, USER_MAX);
3027      }
3028    }
3029
3030  p = sh_unix_getUIDdir (SH_ERR_ERR, sruid, dir, sizeof(dir));
3031
3032  if (p == NULL)
3033    SL_RETURN((-1), _("sh_unix_getUser"));
3034  else
3035    {
3036      if (sl_strlen(p) >= SH_PATHBUF) {
3037        sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_PWLONG,
3038                         _("getpwuid"), (long) sruid, _("pw_home"));
3039        SL_RETURN((-1), _("sh_unix_getUser"));
3040      } else {
3041        sl_strlcpy ( sh.real.home, p, SH_PATHBUF);
3042      }
3043    }
3044
3045  SL_RETURN((0), _("sh_unix_getUser"));
3046
3047  /* notreached */
3048}
3049
3050
3051int sh_unix_getline (SL_TICKET fd, char * line, int sizeofline)
3052{
3053  register int  count;
3054  register int  n = 0;
3055  char          c;
3056
3057  SL_ENTER(_("sh_unix_getline"));
3058
3059  if (sizeofline < 2) {
3060    line[0] = '\0';
3061    SL_RETURN((0), _("sh_unix_getline"));
3062  }
3063
3064  --sizeofline;
3065
3066  while (n < sizeofline) {
3067
3068    count = sl_read (fd, &c, 1);
3069
3070    /* end of file
3071     */
3072    if (count < 1) {
3073      line[n] = '\0';
3074      n = -1;
3075      break;
3076    } 
3077
3078    if (/* c != '\0' && */ c != '\n') {
3079      line[n] = c;
3080      ++n;
3081    } else if (c == '\n') {
3082      if (n > 0) {
3083        line[n] = '\0';
3084        break;
3085      } else {
3086        line[n] = '\n'; /* get newline only if only char on line */
3087        ++n;
3088        line[n] = '\0';
3089        break;
3090      }
3091    } else {
3092      line[n] = '\0';
3093      break;
3094    }
3095
3096  }
3097
3098
3099  line[sizeofline] = '\0';  /* make sure line is terminated */
3100  SL_RETURN((n), _("sh_unix_getline"));
3101}
3102
3103
3104#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
3105
3106/**************************************************************
3107 *
3108 * --- FILE INFO ---
3109 *
3110 **************************************************************/
3111
3112#if (defined(__linux__) && (defined(HAVE_LINUX_EXT2_FS_H) || defined(HAVE_EXT2FS_EXT2_FS_H))) || defined(HAVE_STAT_FLAGS)
3113
3114#if defined(__linux__)
3115
3116/* --- Determine ext2fs file attributes. ---
3117 */
3118#include <sys/ioctl.h>
3119#if defined(HAVE_EXT2FS_EXT2_FS_H)
3120#include <ext2fs/ext2_fs.h>
3121#else
3122#include <linux/ext2_fs.h>
3123#endif
3124
3125/* __linux__ includes */
3126#endif
3127
3128static 
3129int sh_unix_getinfo_attr (char * name, 
3130                          unsigned long * flags, 
3131                          char * c_attr,
3132                          int fd, struct stat * buf)
3133{
3134
3135/* TAKEN FROM:
3136 *
3137 * lsattr.c             - List file attributes on an ext2 file system
3138 *
3139 * Copyright (C) 1993, 1994  Remy Card <card@masi.ibp.fr>
3140 *                           Laboratoire MASI, Institut Blaise Pascal
3141 *                           Universite Pierre et Marie Curie (Paris VI)
3142 *
3143 * This file can be redistributed under the terms of the GNU General
3144 * Public License
3145 */
3146
3147#ifdef HAVE_STAT_FLAGS
3148
3149  SL_ENTER(_("sh_unix_getinfo_attr"));
3150
3151  *flags = 0;
3152
3153  /* cast to void to avoid compiler warning about unused parameters */
3154  (void) fd;
3155  (void) name;
3156
3157#ifdef UF_NODUMP
3158  if (buf->st_flags & UF_NODUMP) {
3159    *flags |= UF_NODUMP;
3160    c_attr[0] = 'd';
3161  }
3162#endif
3163#ifdef UF_IMMUTABLE
3164  if (buf->st_flags & UF_IMMUTABLE) {
3165    *flags |= UF_IMMUTABLE;
3166    c_attr[1] = 'i';
3167  }
3168#endif
3169#ifdef UF_APPEND
3170  if (buf->st_flags & UF_APPEND) {
3171    *flags |= UF_APPEND;
3172    c_attr[2] = 'a';
3173  }
3174#endif
3175#ifdef UF_NOUNLINK
3176  if (buf->st_flags & UF_NOUNLINK) {
3177    *flags |= UF_NOUNLINK;
3178    c_attr[3] = 'u';
3179  }
3180#endif
3181#ifdef UF_OPAQUE
3182  if (buf->st_flags & UF_OPAQUE) {
3183    *flags |= UF_OPAQUE;
3184    c_attr[4] = 'o';
3185  }
3186#endif
3187#ifdef SF_ARCHIVED
3188  if (buf->st_flags & SF_ARCHIVED) {
3189    *flags |= SF_ARCHIVED;
3190    c_attr[5] = 'R';
3191  }
3192   
3193#endif
3194#ifdef SF_IMMUTABLE
3195  if (buf->st_flags & SF_IMMUTABLE) {
3196    *flags |= SF_IMMUTABLE;
3197    c_attr[6] = 'I';
3198  }
3199#endif
3200#ifdef SF_APPEND
3201  if (buf->st_flags & SF_APPEND) {
3202    *flags |= SF_APPEND;
3203    c_attr[7] = 'A';
3204  }
3205#endif
3206#ifdef SF_NOUNLINK
3207  if (buf->st_flags & SF_NOUNLINK) {
3208    *flags |= SF_NOUNLINK;
3209    c_attr[8] = 'U';
3210  }
3211#endif
3212
3213  /* ! HAVE_STAT_FLAGS */
3214#else
3215
3216#ifdef HAVE_EXT2_IOCTLS
3217  int /* fd, */ r, f;
3218 
3219  SL_ENTER(_("sh_unix_getinfo_attr"));
3220
3221  *flags = 0;
3222  (void) buf;
3223
3224  /* open() -> aud_open() R.Wichmann
3225  fd = aud_open (FIL__, __LINE__, SL_YESPRIV, name, O_RDONLY|O_NONBLOCK, 0);
3226  */
3227
3228  if (fd == -1 || name == NULL)
3229    SL_RETURN(-1, _("sh_unix_getinfo_attr"));
3230
3231 
3232  r = ioctl (fd, EXT2_IOC_GETFLAGS, &f);
3233  /* sl_close_fd (FIL__, __LINE__, fd); */
3234
3235  if (r == -1)
3236    SL_RETURN(-1, _("sh_unix_getinfo_attr"));
3237
3238  if (f == 0)
3239    SL_RETURN(0, _("sh_unix_getinfo_attr"));
3240
3241  *flags = f;
3242
3243/* ! HAVE_EXT2_IOCTLS */
3244#else
3245
3246  SL_ENTER(_("sh_unix_getinfo_attr"));
3247
3248  *flags = 0;                                     /* modified by R.Wichmann */
3249
3250/* ! HAVE_EXT2_IOCTLS */
3251#endif
3252/*
3253 * END
3254 *
3255 * lsattr.c             - List file attributes on an ext2 file system
3256 */
3257
3258  if (*flags == 0)
3259    goto theend;
3260
3261#ifdef EXT2_SECRM_FL
3262  if ( (*flags & EXT2_SECRM_FL) != 0  )   c_attr[0] = 's';
3263#endif
3264#ifdef EXT2_UNRM_FL
3265  if ( (*flags & EXT2_UNRM_FL) != 0   )   c_attr[1] = 'u';
3266#endif
3267#ifdef EXT2_SYNC_FL
3268  if ( (*flags & EXT2_SYNC_FL) != 0    )  c_attr[2] = 'S';
3269#endif
3270#ifdef EXT2_IMMUTABLE_FL
3271  if ( (*flags & EXT2_IMMUTABLE_FL) != 0) c_attr[3] = 'i';
3272#endif
3273#ifdef EXT2_APPEND_FL
3274  if ( (*flags & EXT2_APPEND_FL) != 0  )  c_attr[4] = 'a';
3275#endif
3276#ifdef EXT2_NODUMP_FL
3277  if ( (*flags & EXT2_NODUMP_FL) != 0  )  c_attr[5] = 'd';
3278#endif
3279#ifdef EXT2_NOATIME_FL
3280  if ( (*flags & EXT2_NOATIME_FL) != 0)   c_attr[6] = 'A';
3281#endif
3282#ifdef EXT2_COMPR_FL
3283  if ( (*flags & EXT2_COMPR_FL) != 0   )  c_attr[7] = 'c';
3284#endif
3285
3286#ifdef EXT2_TOPDIR_FL
3287  if ( (*flags & EXT2_TOPDIR_FL) != 0  )  c_attr[8] = 'T';
3288#endif
3289#ifdef EXT2_DIRSYNC_FL
3290  if ( (*flags & EXT2_DIRSYNC_FL) != 0 )  c_attr[9] = 'D';
3291#endif
3292#ifdef EXT2_NOTAIL_FL
3293  if ( (*flags & EXT2_NOTAIL_FL) != 0  )  c_attr[10] = 't';
3294#endif
3295#ifdef EXT2_JOURNAL_DATA_FL
3296  if ( (*flags & EXT2_JOURNAL_DATA_FL) != 0)  c_attr[11] = 'j';
3297#endif
3298
3299 theend:
3300  /* ext2 */
3301#endif
3302
3303  c_attr[12] = '\0';
3304
3305  SL_RETURN(0, _("sh_unix_getinfo_attr"));
3306}
3307
3308/* defined(__linux__) || defined(HAVE_STAT_FLAGS) */
3309#endif
3310
3311/* determine file type
3312 */
3313static 
3314int sh_unix_getinfo_type (struct stat * buf, 
3315                          ShFileType * type, 
3316                          char * c_mode)
3317{
3318  SL_ENTER(_("sh_unix_getinfo_type"));
3319
3320  if      ( S_ISREG(buf->st_mode)  ) { 
3321    (*type)   = SH_FILE_REGULAR;
3322    c_mode[0] = '-';
3323  }
3324  else if ( S_ISLNK(buf->st_mode)  ) {
3325    (*type)   = SH_FILE_SYMLINK;
3326    c_mode[0] = 'l';
3327  }
3328  else if ( S_ISDIR(buf->st_mode)  ) {
3329    (*type)   = SH_FILE_DIRECTORY;
3330    c_mode[0] = 'd';
3331  }
3332  else if ( S_ISCHR(buf->st_mode)  ) {
3333    (*type)   = SH_FILE_CDEV;
3334    c_mode[0] = 'c';
3335  }
3336  else if ( S_ISBLK(buf->st_mode)  ) {
3337    (*type)   = SH_FILE_BDEV;
3338    c_mode[0] = 'b';
3339  }
3340  else if ( S_ISFIFO(buf->st_mode) ) {
3341    (*type)   = SH_FILE_FIFO;
3342    c_mode[0] = '|';
3343  }
3344  else if ( S_ISSOCK(buf->st_mode) ) {
3345    (*type)   = SH_FILE_SOCKET;
3346    c_mode[0] = 's';
3347  }
3348  else if ( S_ISDOOR(buf->st_mode) ) {
3349    (*type)   = SH_FILE_DOOR;
3350    c_mode[0] = 'D';
3351  }
3352  else if ( S_ISPORT(buf->st_mode) ) {
3353    (*type)   = SH_FILE_PORT;
3354    c_mode[0] = 'P';
3355  }
3356  else                              {
3357    (*type)   = SH_FILE_UNKNOWN;
3358    c_mode[0] = '?';
3359  }
3360
3361  SL_RETURN(0, _("sh_unix_getinfo_type"));
3362}
3363
3364int sh_unix_get_ftype(char * fullpath)
3365{
3366  char        c_mode[CMODE_SIZE];
3367  struct stat buf;
3368  ShFileType  type;
3369  int         res;
3370
3371  SL_ENTER(_("sh_unix_get_ftype"));
3372
3373  res = retry_lstat(FIL__, __LINE__, fullpath, &buf);
3374
3375  if (res < 0)
3376    SL_RETURN(SH_FILE_UNKNOWN, _("sh_unix_getinfo_type"));
3377
3378  sh_unix_getinfo_type (&buf, &type, c_mode);
3379
3380  SL_RETURN(type, _("sh_unix_get_ftype"));
3381}
3382
3383
3384static 
3385int  sh_unix_getinfo_mode (struct stat *buf, 
3386                           unsigned int * mode, 
3387                           char * c_mode)
3388{
3389
3390  SL_ENTER(_("sh_unix_getinfo_mode"));
3391
3392  (*mode) = buf->st_mode;
3393
3394  /* make 'ls'-like string */
3395 
3396  if ( (buf->st_mode & S_IRUSR) != 0 )  c_mode[1] = 'r'; 
3397  if ( (buf->st_mode & S_IWUSR) != 0 )  c_mode[2] = 'w'; 
3398  if ( (buf->st_mode & S_IXUSR) != 0 ) {
3399    if ((buf->st_mode & S_ISUID) != 0 ) c_mode[3] = 's';
3400    else                                c_mode[3] = 'x';
3401  } else {
3402    if ((buf->st_mode & S_ISUID) != 0 ) c_mode[3] = 'S';
3403  }
3404
3405  if ( (buf->st_mode & S_IRGRP) != 0 )  c_mode[4] = 'r'; 
3406  if ( (buf->st_mode & S_IWGRP) != 0 )  c_mode[5] = 'w'; 
3407  if ( (buf->st_mode & S_IXGRP) != 0 )  {
3408    if ((buf->st_mode & S_ISGID) != 0 ) c_mode[6] = 's';
3409    else                                c_mode[6] = 'x';
3410  } else {
3411    if ((buf->st_mode & S_ISGID) != 0 ) c_mode[6] = 'S';
3412  } 
3413
3414  if ( (buf->st_mode & S_IROTH) != 0 )  c_mode[7] = 'r'; 
3415  if ( (buf->st_mode & S_IWOTH) != 0 )  c_mode[8] = 'w';
3416#ifdef S_ISVTX  /* not POSIX */
3417  if ( (buf->st_mode & S_IXOTH) != 0 )  {
3418    if ((buf->st_mode & S_ISVTX) != 0 ) c_mode[9] = 't';
3419    else                                c_mode[9] = 'x';
3420  } else {
3421    if ((buf->st_mode & S_ISVTX) != 0 ) c_mode[9] = 'T';
3422  }
3423#else
3424  if ( (buf->st_mode & S_IXOTH) != 0 )  c_mode[9] = 'x';
3425#endif
3426
3427  SL_RETURN(0, _("sh_unix_getinfo_mode"));
3428}
3429
3430
3431long IO_Limit = 0;
3432
3433void sh_unix_io_pause ()
3434{
3435  long runtime;
3436  float          someval;
3437  unsigned long  sometime;
3438
3439  if (IO_Limit == 0)
3440    {
3441      return;
3442    }
3443  else
3444    {
3445      runtime = (long) (time(NULL) - sh.statistics.time_start);
3446     
3447      if (runtime > 0 && (long)(sh.statistics.bytes_hashed/runtime) > IO_Limit)
3448        {
3449          someval  = sh.statistics.bytes_hashed - (IO_Limit * runtime);
3450          someval /= (float) IO_Limit;
3451          if (someval < 1.0)
3452            {
3453              someval *= 1000;  /* milliseconds in a second */
3454              sometime = (unsigned long) someval;
3455              retry_msleep(0, sometime);
3456            }
3457          else
3458            {
3459              sometime = (unsigned long) someval;
3460              retry_msleep (sometime, 0);
3461            }
3462        }
3463    }
3464  return;
3465}
3466
3467int sh_unix_set_io_limit (const char * c)
3468{
3469  long val;
3470
3471  SL_ENTER(_("sh_unix_set_io_limit"));
3472
3473  val = strtol (c, (char **)NULL, 10);
3474  if (val < 0)
3475    sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
3476                      _("set I/O limit"), c);
3477
3478  val = (val < 0 ? 0 : val);
3479
3480  IO_Limit = val * 1024;
3481  SL_RETURN( 0, _("sh_unix_set_io_limit"));
3482}
3483
3484/* obtain file info
3485 */
3486extern int flag_err_debug;
3487
3488#include "sh_ignore.h"
3489
3490int sh_unix_checksum_size (char * filename, off_t size, int is_max_size, 
3491                           char * fileHash, int alert_timeout, SL_TICKET fd, unsigned long mask)
3492{
3493  file_type * tmpFile;
3494  int status;
3495
3496  SL_ENTER(_("sh_unix_checksum_size"));
3497
3498  tmpFile = SH_ALLOC(sizeof(file_type));
3499  tmpFile->link_path = NULL;
3500
3501  if (sh.flag.checkSum != SH_CHECK_INIT)
3502    {
3503      /* lookup file in database */
3504      if (is_max_size == S_TRUE) {
3505        status = sh_hash_get_it (filename, tmpFile, NULL);
3506        if ((status != 0) || (tmpFile->size > size)) {
3507          goto out;
3508        }
3509      } else {
3510        tmpFile->size = size;
3511      }
3512    }
3513  else
3514    {
3515      tmpFile->size = size;
3516    }
3517
3518  /* if last <= current get checksum */
3519  if (tmpFile->size <= size)
3520    {
3521      char hashbuf[KEYBUF_SIZE];
3522      UINT64 local_length = (UINT64) (tmpFile->size < 0 ? 0 : tmpFile->size);
3523      if (sh.flag.opts == S_TRUE) sh_tiger_set_hashtype_mask(mask);
3524      sl_strlcpy(fileHash,
3525                 sh_tiger_generic_hash (filename, fd, &(local_length), 
3526                                        alert_timeout, hashbuf, sizeof(hashbuf)),
3527                 KEY_LEN+1);
3528     
3529       /* return */
3530      if (tmpFile->link_path)   SH_FREE(tmpFile->link_path);
3531      SH_FREE(tmpFile);
3532      SL_RETURN( 0, _("sh_unix_checksum_size"));
3533    }
3534
3535 out:
3536  if (tmpFile->link_path)   SH_FREE(tmpFile->link_path);
3537  SH_FREE(tmpFile);
3538  sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
3539  SL_RETURN( -1, _("sh_unix_checksum_size"));
3540}
3541
3542/********************************************************
3543 * Search rotated logfile
3544 */
3545extern char * sh_rotated_log_search(const char * path, struct stat * buf);
3546
3547int sh_check_rotated_log (const char * path, 
3548                          UINT64 old_size, UINT64 old_inode, const char * old_hash, unsigned long mask)
3549{
3550  struct stat obuf;
3551  UINT64 length_nolim = TIGER_NOLIM;
3552  int retval = S_FALSE;
3553
3554  if (old_size != length_nolim)
3555    {
3556      char hashbuf[KEYBUF_SIZE];
3557      char * rotated_file;
3558
3559      obuf.st_ino = old_inode;
3560      rotated_file = sh_rotated_log_search(path, &obuf);
3561
3562      if (rotated_file && (0 != strcmp(path, rotated_file)))
3563        {
3564          SL_TICKET fd = sl_open_fastread (FIL__, __LINE__, rotated_file, SL_YESPRIV);
3565          if (!SL_ISERROR(fd))
3566            {
3567              sh_unix_checksum_size (rotated_file, old_size, S_FALSE, 
3568                                     hashbuf, 120 /* alert_timeout */, fd, mask);
3569             
3570              sl_close(fd);
3571             
3572              if (strncmp (old_hash, hashbuf, KEY_LEN) == 0) {
3573                retval = S_TRUE;
3574              }
3575            }
3576          SH_FREE(rotated_file);
3577        }
3578    }
3579  return retval;
3580}
3581
3582
3583int sh_unix_check_selinux = S_FALSE;
3584int sh_unix_check_acl     = S_FALSE;
3585
3586#ifdef USE_ACL
3587
3588#include <sys/acl.h>
3589static char * sh_unix_getinfo_acl (char * path, int fd, struct stat * buf)
3590{
3591  /* system.posix_acl_access, system.posix_acl_default
3592   */
3593  char *  out  = NULL;
3594  char *  collect = NULL;
3595  char *  tmp;
3596  char *  out_compact;
3597  ssize_t len;
3598  acl_t   result;
3599
3600  SL_ENTER(_("sh_unix_getinfo_acl"));
3601
3602  result = (fd == -1) ? 
3603    acl_get_file (path, ACL_TYPE_ACCESS) :
3604    acl_get_fd   (fd);
3605
3606  if (result)
3607    {
3608      out = acl_to_text (result, &len);
3609      if (out && (len > 0)) {
3610        out_compact = sh_util_acl_compact (out, len);
3611        acl_free(out);
3612        if (out_compact) 
3613          {
3614            collect = sh_util_strconcat (_("acl_access:"), out_compact, NULL);
3615            SH_FREE(out_compact);
3616          }
3617      }
3618      acl_free(result);
3619    }
3620 
3621 
3622  if ( S_ISDIR(buf->st_mode) ) 
3623    {
3624      result = acl_get_file (path, ACL_TYPE_DEFAULT);
3625     
3626      if (result)
3627        {
3628          out = acl_to_text (result, &len);
3629          if (out && (len > 0)) {
3630            out_compact = sh_util_acl_compact (out, len);
3631            acl_free(out);
3632            if (out_compact) {
3633              if (collect) {
3634                tmp = sh_util_strconcat (_("acl_default:"), 
3635                                         out_compact, ":", collect, NULL);
3636                SH_FREE(collect);
3637              }
3638              else {
3639                tmp = sh_util_strconcat (_("acl_default:"), out_compact, NULL);
3640              }
3641              SH_FREE(out_compact);
3642              collect = tmp;
3643            }
3644          }
3645          acl_free(result);
3646        }
3647    }
3648 
3649  SL_RETURN((collect),_("sh_unix_getinfo_acl"));
3650}
3651#endif
3652
3653#ifdef USE_XATTR
3654
3655#include <attr/xattr.h>
3656static char * sh_unix_getinfo_xattr_int (char * path, int fd, char * name)
3657{
3658  char *  out   = NULL;
3659  char *  tmp   = NULL;
3660  size_t  size  = 256;
3661  ssize_t result;
3662
3663  SL_ENTER(_("sh_unix_getinfo_xattr_int"));
3664
3665  out = SH_ALLOC(size);
3666
3667  result = (fd == -1) ? 
3668    lgetxattr (path, name, out, size-1) :
3669    fgetxattr (fd,   name, out, size-1);
3670
3671  if (result == -1 && errno == ERANGE) 
3672    {
3673      SH_FREE(out);
3674      result = (fd == -1) ? 
3675        lgetxattr (path, name, NULL, 0) :
3676        fgetxattr (fd,   name, NULL, 0);
3677      size = result + 1;
3678      out  = SH_ALLOC(size);
3679      result = (fd == -1) ? 
3680        lgetxattr (path, name, out, size-1) :
3681        fgetxattr (fd,   name, out, size-1);
3682    }
3683
3684  if ((result > 0) && ((size_t)result < size))
3685    {
3686      out[size-1] = '\0';
3687      tmp = out;
3688    }
3689  else
3690    {
3691      SH_FREE(out);
3692    }
3693
3694  SL_RETURN((tmp),_("sh_unix_getinfo_xattr_int"));
3695}
3696
3697
3698static char * sh_unix_getinfo_xattr (char * path, int fd, struct stat * buf)
3699{
3700  /* system.posix_acl_access, system.posix_acl_default, security.selinux
3701   */
3702  char *  tmp;
3703  char *  out  = NULL;
3704  char *  collect = NULL;
3705
3706  SL_ENTER(_("sh_unix_getinfo_xattr"));
3707
3708#ifdef USE_ACL
3709  /*
3710   * we need the acl_get_fd/acl_get_file functions, getxattr will only
3711   * yield the raw bytes
3712   */
3713  if (sh_unix_check_acl == S_TRUE) 
3714    {
3715      out = sh_unix_getinfo_acl(path, fd, buf);
3716     
3717      if (out)
3718        {
3719          collect = out;
3720        }
3721  }
3722#else
3723  (void) buf;
3724#endif
3725
3726  if (sh_unix_check_selinux == S_TRUE)
3727    {
3728      out = sh_unix_getinfo_xattr_int(path, fd, _("security.selinux"));
3729
3730      if (out)
3731        {
3732          if (collect) {
3733            tmp = sh_util_strconcat(_("selinux:"), out, ":", collect, NULL);
3734            SH_FREE(collect);
3735          }
3736          else {
3737            tmp = sh_util_strconcat(_("selinux:"), out, NULL);
3738          }
3739          SH_FREE(out);
3740          collect = tmp;
3741        }
3742    }
3743
3744  SL_RETURN((collect),_("sh_unix_getinfo_xattr"));
3745}
3746#endif
3747
3748#ifdef USE_XATTR
3749int sh_unix_setcheckselinux (const char * c)
3750{
3751  int i;
3752  SL_ENTER(_("sh_unix_setcheckselinux"));
3753  i = sh_util_flagval(c, &(sh_unix_check_selinux));
3754
3755  SL_RETURN(i, _("sh_unix_setcheckselinux"));
3756}
3757#endif
3758
3759#ifdef USE_ACL
3760int sh_unix_setcheckacl (const char * c)
3761{
3762  int i;
3763  SL_ENTER(_("sh_unix_setcheckacl"));
3764  i = sh_util_flagval(c, &(sh_unix_check_acl));
3765
3766  SL_RETURN(i, _("sh_unix_setcheckacl"));
3767}
3768#endif
3769
3770#ifdef HAVE_LIBZ
3771#include <zlib.h>
3772#endif   
3773
3774
3775static void * sh_dummy_filename;
3776static void * sh_dummy_tmp;
3777static void * sh_dummy_tmp2;
3778
3779int sh_unix_getinfo (int level, const char * filename, file_type * theFile, 
3780                     char * fileHash, int policy)
3781{
3782  char          timestr[81];
3783  long          runtim;
3784  struct stat   buf;
3785  struct stat   lbuf;
3786  struct stat   fbuf;
3787  volatile int  stat_return;
3788  volatile int  stat_errno = 0;
3789
3790  ShFileType    type;
3791  unsigned int  mode;
3792  char        * tmp;
3793  char        * tmp2;
3794
3795  char        * linknamebuf;
3796  volatile int  linksize;
3797
3798  extern int get_the_fd (SL_TICKET ticket);
3799
3800  volatile SL_TICKET     rval_open;
3801  volatile int           err_open = 0;
3802
3803  volatile int           fd;
3804  volatile int           fstat_return;
3805  volatile int           fstat_errno = 0;
3806  volatile int           try         = 0;
3807
3808  sh_string   * content = NULL;
3809     
3810  time_t        tend;
3811  time_t        tstart;
3812
3813
3814  char * path = NULL;
3815
3816  volatile int alert_timeout   = 120;
3817
3818  path = theFile->fullpath;
3819
3820  SL_ENTER(_("sh_unix_getinfo"));
3821
3822  if (!MODI_INITIALIZED(theFile->check_flags))
3823    {
3824      tmp2 = sh_util_safe_name (theFile->fullpath);
3825      SH_MUTEX_LOCK(mutex_thread_nolog);
3826      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGPATH,
3827                       _("Uninitialized check mask"), _("sh_unix_getinfo"),
3828                       tmp2);
3829      SH_MUTEX_UNLOCK(mutex_thread_nolog);
3830      SH_FREE(tmp2);
3831      SL_RETURN((-1),_("sh_unix_getinfo"));
3832    }
3833
3834  /* Take the address to keep gcc from putting it into a register.
3835   * Avoids the 'clobbered by longjmp' warning.
3836   */
3837  sh_dummy_filename = (void *) &filename;
3838  sh_dummy_tmp      = (void *) &tmp;
3839  sh_dummy_tmp2     = (void *) &tmp2;
3840
3841  /* --- Stat the file, and get checksum. ---
3842   */
3843  tstart = time(NULL);
3844
3845  stat_return = retry_lstat (FIL__, __LINE__, 
3846                             path /* theFile->fullpath */, &buf);
3847
3848  if (stat_return)
3849    stat_errno = errno;
3850
3851  theFile->link_path = NULL;
3852
3853 try_again:
3854
3855  fd           = -1;
3856  fstat_return = -1;
3857  rval_open    = -1;
3858
3859  if (stat_return == 0 && S_ISREG(buf.st_mode)) 
3860    {
3861      rval_open = sl_open_fastread (FIL__, __LINE__, 
3862                                    path /* theFile->fullpath */, SL_YESPRIV);
3863      if (SL_ISERROR(rval_open))
3864        {
3865          char * stale = sl_check_stale();
3866         
3867          if (stale)
3868            {
3869              SH_MUTEX_LOCK(mutex_thread_nolog);
3870              sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, err_open, MSG_E_SUBGEN,
3871                              stale, _("sh_unix_getinfo_open"));
3872              SH_MUTEX_UNLOCK(mutex_thread_nolog);
3873            }
3874
3875          if (errno == EBADF && try == 0) /* obsolete, but we keep this, just in case */
3876            {
3877              ++try;
3878              goto try_again;
3879            }
3880          err_open = errno;
3881        }
3882
3883      alert_timeout = 120; /* this is per 8K block now ! */
3884
3885      if (path[1] == 'p' && path[5] == '/' && path[2] == 'r' &&
3886          path[3] == 'o' && path[4] == 'c' && path[0] == '/')
3887        {
3888          /* seven is magic */
3889          alert_timeout = 7;
3890        }
3891
3892      fd = get_the_fd(rval_open);
3893    }
3894
3895  tend = time(NULL);
3896
3897  /* An unprivileged user may slow lstat/open to a crawl
3898   * with clever path/symlink setup
3899   */
3900  if ((tend - tstart) > (time_t) /* 60 */ 6)
3901    {
3902      tmp2 = sh_util_safe_name (theFile->fullpath);
3903      SH_MUTEX_LOCK(mutex_thread_nolog);
3904      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_TOOLATE,
3905                       (long)(tend - tstart), tmp2);
3906      SH_MUTEX_UNLOCK(mutex_thread_nolog);
3907      SH_FREE(tmp2);
3908    }
3909
3910  if (fd >= 0) 
3911    {
3912      fstat_return = retry_fstat (FIL__, __LINE__, fd, &fbuf);
3913
3914      if (fstat_return)
3915        {
3916          char * stale;
3917
3918          fstat_errno = errno;
3919
3920          stale = sl_check_stale();
3921
3922          if (stale)
3923            {
3924              SH_MUTEX_LOCK(mutex_thread_nolog);
3925              sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, fstat_errno, 
3926                              MSG_E_SUBGEN,
3927                              stale, _("sh_unix_getinfo_fstat"));
3928              SH_MUTEX_UNLOCK(mutex_thread_nolog);
3929            }
3930
3931          if (try == 0) /* obsolete, but we keep this, just in case */
3932            {
3933              ++try;
3934              sl_close(rval_open);
3935              goto try_again;
3936            }
3937        }
3938    }
3939  else
3940    {
3941      fd = -1;
3942    }
3943     
3944
3945  /* ---  case 1: lstat failed  ---
3946   */
3947  if (stat_return != 0) 
3948    {
3949      stat_return = errno;
3950      if (!SL_ISERROR(rval_open))
3951          sl_close(rval_open);
3952      if (sh.flag.checkSum == SH_CHECK_INIT || 
3953          (sh_hash_have_it (theFile->fullpath) >= 0 && 
3954           (!SH_FFLAG_REPORTED_SET(theFile->file_reported))))
3955        {
3956          if (S_FALSE == sh_ignore_chk_del(theFile->fullpath)) {
3957            int flags = sh_hash_getflags (theFile->fullpath);
3958
3959            if ((flags >= 0) && (flags & SH_FFLAG_ENOENT) == 0) {
3960              char errbuf[SH_ERRBUF_SIZE];
3961              uid_t euid;
3962              (void) sl_get_euid(&euid);
3963              tmp2 = sh_util_safe_name (theFile->fullpath);
3964              SH_MUTEX_LOCK(mutex_thread_nolog);
3965              sh_error_handle (level, FIL__, __LINE__, stat_return, MSG_FI_STAT,
3966                               _("lstat"),
3967                               sh_error_message (stat_errno, errbuf, sizeof(errbuf)),
3968                               (long) euid,
3969                               tmp2);
3970              SH_MUTEX_UNLOCK(mutex_thread_nolog);
3971              SH_FREE(tmp2);
3972              sh_hash_set_flag (theFile->fullpath, SH_FFLAG_ENOENT);
3973            }
3974          }
3975        }
3976      SL_RETURN((-1),_("sh_unix_getinfo"));
3977    }
3978
3979  /* ---  case 2: not a regular file  ---
3980   */
3981  else if (! S_ISREG(buf.st_mode))
3982    {
3983      if (fileHash != NULL)
3984        sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
3985    }
3986 
3987  /* ---  case 3a: a regular file, fstat ok ---
3988   */
3989  else if (fstat_return == 0 && 
3990           buf.st_mode == fbuf.st_mode &&
3991           buf.st_ino  == fbuf.st_ino  &&
3992           buf.st_uid  == fbuf.st_uid  &&
3993           buf.st_gid  == fbuf.st_gid  &&
3994           buf.st_dev  == fbuf.st_dev )
3995    {
3996      if (fileHash != NULL)
3997        {
3998          if ((theFile->check_flags & MODI_CHK) == 0 ||
3999              sh_restrict_this(theFile->fullpath, (UINT64) fbuf.st_size, 
4000                               (UINT64) fbuf.st_mode, rval_open))
4001            {
4002              sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
4003            }
4004          else if ((theFile->check_flags & MODI_PREL) != 0 &&
4005                   S_TRUE == sh_prelink_iself(rval_open, fbuf.st_size, 
4006                                              alert_timeout, theFile->fullpath))
4007            {
4008              if (0 != sh_prelink_run (theFile->fullpath, 
4009                                       fileHash, alert_timeout, theFile->check_flags))
4010                sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
4011            }
4012          else
4013            {
4014              char hashbuf[KEYBUF_SIZE];
4015              UINT64 length_current = TIGER_NOLIM;
4016
4017              if (MODI_TXT_ENABLED(theFile->check_flags) && fbuf.st_size < (10 * SH_TXT_MAX))
4018                {
4019                  sl_init_content (rval_open, fbuf.st_size);
4020                }
4021
4022              if (sh.flag.opts == S_TRUE) sh_tiger_set_hashtype_mask(theFile->check_flags);
4023              sl_strlcpy(fileHash,
4024                         sh_tiger_generic_hash (theFile->fullpath, 
4025                                                rval_open, &length_current, 
4026                                                alert_timeout, 
4027                                                hashbuf, sizeof(hashbuf)),
4028                         KEY_LEN+1);
4029
4030              content = sl_get_content(rval_open);
4031              content = sh_string_copy(content);
4032
4033              if ((theFile->check_flags & MODI_SGROW) != 0)
4034                {
4035                  /* Update size so it matches the one for which the checksum
4036                     has been computed */
4037                  fbuf.st_size = length_current;
4038                  buf.st_size  = fbuf.st_size;
4039                  sl_rewind(rval_open);
4040                  sh_unix_checksum_size (theFile->fullpath, length_current, S_TRUE,
4041                                         &fileHash[KEY_LEN + 1], 
4042                                         alert_timeout, rval_open, theFile->check_flags);
4043                }
4044            }
4045        }
4046    }
4047
4048  /* ---  case 3b: a regular file, fstat ok, but different ---
4049   */
4050  else if (fstat_return == 0 && S_ISREG(fbuf.st_mode))
4051    {
4052      memcpy (&buf, &fbuf, sizeof( struct stat ));
4053
4054      if (fileHash != NULL)
4055        {
4056          if ((theFile->check_flags & MODI_CHK) == 0 ||
4057              sh_restrict_this(theFile->fullpath, (UINT64) fbuf.st_size, 
4058                               (UINT64) fbuf.st_mode, rval_open))
4059            {
4060              sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
4061            }
4062          else if (policy == SH_LEVEL_PRELINK &&
4063                   S_TRUE == sh_prelink_iself(rval_open, fbuf.st_size, 
4064                                              alert_timeout, theFile->fullpath))
4065            {
4066              if (0 != sh_prelink_run (theFile->fullpath, 
4067                                       fileHash, alert_timeout, theFile->check_flags))
4068                sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
4069            }
4070          else
4071            {
4072              char hashbuf[KEYBUF_SIZE];
4073              UINT64 length_current = TIGER_NOLIM;
4074
4075              if (MODI_TXT_ENABLED(theFile->check_flags) && fbuf.st_size < (10 * SH_TXT_MAX))
4076                {
4077                  sl_init_content (rval_open, fbuf.st_size);
4078                }
4079
4080              if (sh.flag.opts == S_TRUE) sh_tiger_set_hashtype_mask(theFile->check_flags);
4081              sl_strlcpy(fileHash, 
4082                         sh_tiger_generic_hash (theFile->fullpath, rval_open, 
4083                                                &length_current,
4084                                                alert_timeout,
4085                                                hashbuf, sizeof(hashbuf)),
4086                         KEY_LEN + 1);
4087
4088              content = sl_get_content(rval_open);
4089              content = sh_string_copy(content);
4090
4091              if ((theFile->check_flags & MODI_SGROW) != 0) 
4092                {
4093                  /* Update size so it matches the one for which the checksum
4094                     has been computed */
4095                  fbuf.st_size = length_current;
4096                  buf.st_size  = fbuf.st_size;
4097                  sl_rewind(rval_open);
4098                  sh_unix_checksum_size (theFile->fullpath, length_current, S_TRUE,
4099                                         &fileHash[KEY_LEN + 1], 
4100                                         alert_timeout, rval_open, theFile->check_flags);
4101                }
4102            }
4103        }
4104    }
4105
4106  /* ---  case 4: a regular file, fstat failed ---
4107   */
4108
4109  else    /* fstat_return != 0 or !S_ISREG(fbuf.st_mode) or open() failed */
4110    {
4111      uid_t   euid;
4112
4113      if (fileHash != NULL)
4114        sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1);
4115
4116      if ((theFile->check_flags & MODI_CHK) != 0)
4117        {
4118          tmp2 = sh_util_safe_name (theFile->fullpath);
4119
4120
4121          if (fd >= 0 && fstat_return != 0)
4122            {
4123              char errbuf[SH_ERRBUF_SIZE];
4124              (void) sl_get_euid(&euid);
4125
4126              SH_MUTEX_LOCK(mutex_thread_nolog);
4127              sh_error_handle (level, FIL__, __LINE__, stat_return, MSG_FI_STAT,
4128                               _("fstat"),
4129                               sh_error_message (fstat_errno, errbuf, sizeof(errbuf)),
4130                               (long) euid,
4131                               tmp2);
4132              SH_MUTEX_UNLOCK(mutex_thread_nolog);
4133            }
4134          else if (fd >= 0 && !S_ISREG(fbuf.st_mode))
4135            {
4136              SH_MUTEX_LOCK(mutex_thread_nolog);
4137              sh_error_handle (level, FIL__, __LINE__, fstat_errno, 
4138                               MSG_E_NOTREG, tmp2);
4139              SH_MUTEX_UNLOCK(mutex_thread_nolog);
4140            }
4141          else
4142            {
4143              char errbuf[SH_ERRBUF_SIZE];
4144              char errbuf2[SH_ERRBUF_SIZE];
4145              sl_strlcpy(errbuf, sl_error_string(rval_open), sizeof(errbuf));
4146              sh_error_message(err_open, errbuf2, sizeof(errbuf2));
4147              SH_MUTEX_LOCK(mutex_thread_nolog);
4148              sh_error_handle (level, FIL__, __LINE__, err_open, 
4149                               MSG_E_READ, errbuf, errbuf2, tmp2);
4150              SH_MUTEX_UNLOCK(mutex_thread_nolog);
4151            }
4152          SH_FREE(tmp2);
4153        }
4154    }     
4155
4156
4157  /* --- Determine file type. ---
4158   */
4159  memset (theFile->c_mode, '-', CMODE_SIZE-1);
4160  theFile->c_mode[CMODE_SIZE-1] = '\0';
4161
4162  memset (theFile->link_c_mode, '-', CMODE_SIZE-1);
4163  theFile->link_c_mode[CMODE_SIZE-1] = '\0';
4164
4165  sh_unix_getinfo_type (&buf, &type, theFile->c_mode);
4166  theFile->type = type;
4167
4168#if defined(__linux__) || defined(HAVE_STAT_FLAGS)
4169
4170  /* --- Determine file attributes. ---
4171   */
4172  memset (theFile->c_attributes, '-', ATTRBUF_SIZE);
4173  theFile->c_attributes[ATTRBUF_USED] = '\0';
4174  theFile->attributes      =    0;
4175
4176#if (defined(__linux__) && (defined(HAVE_LINUX_EXT2_FS_H) || defined(HAVE_EXT2FS_EXT2_FS_H))) || defined(HAVE_STAT_FLAGS)
4177  if (theFile->c_mode[0] != 'c' && theFile->c_mode[0] != 'b' &&
4178      theFile->c_mode[0] != 'l' )
4179    sh_unix_getinfo_attr(theFile->fullpath, 
4180                         &theFile->attributes, theFile->c_attributes, 
4181                         fd, &buf);
4182#endif
4183#endif
4184
4185#if defined(USE_XATTR) && defined(USE_ACL)
4186  if (sh_unix_check_selinux == S_TRUE || sh_unix_check_acl == S_TRUE)
4187    theFile->attr_string = sh_unix_getinfo_xattr (theFile->fullpath, fd, &buf);
4188#elif defined(USE_XATTR)
4189  if (sh_unix_check_selinux == S_TRUE)
4190    theFile->attr_string = sh_unix_getinfo_xattr (theFile->fullpath, fd, &buf);
4191#elif defined(USE_ACL)
4192  if (sh_unix_check_acl == S_TRUE)
4193    theFile->attr_string = sh_unix_getinfo_acl (theFile->fullpath, fd, &buf);
4194#else
4195  theFile->attr_string = NULL;
4196#endif
4197
4198  if (!SL_ISERROR(rval_open))
4199    sl_close(rval_open);
4200
4201
4202  /* --- I/O limit. ---
4203   */
4204  if (IO_Limit > 0)
4205    {
4206      runtim = (long) (time(NULL) - sh.statistics.time_start);
4207     
4208      if (runtim > 0 && (long)(sh.statistics.bytes_hashed/runtim) > IO_Limit)
4209        retry_msleep(1, 0);
4210    }
4211
4212  /* --- Determine permissions. ---
4213   */
4214  sh_unix_getinfo_mode (&buf, &mode, theFile->c_mode);
4215
4216  /* --- Trivia. ---
4217   */
4218  theFile->dev       = buf.st_dev;
4219  theFile->ino       = buf.st_ino;
4220  theFile->mode      = buf.st_mode;
4221  theFile->hardlinks = buf.st_nlink;
4222  theFile->owner     = buf.st_uid; 
4223  theFile->group     = buf.st_gid; 
4224  theFile->rdev      = buf.st_rdev;
4225  theFile->size      = buf.st_size;
4226  theFile->blksize   = (unsigned long) buf.st_blksize;
4227  theFile->blocks    = (unsigned long) buf.st_blocks;
4228  theFile->atime     = buf.st_atime;
4229  theFile->mtime     = buf.st_mtime;
4230  theFile->ctime     = buf.st_ctime;
4231
4232
4233  /* --- Owner and group. ---
4234   */
4235
4236  if (NULL == sh_unix_getGIDname(SH_ERR_ALL, buf.st_gid, theFile->c_group, GROUP_MAX+1)) {
4237
4238    tmp2 = sh_util_safe_name (theFile->fullpath);
4239
4240    if (policy == SH_LEVEL_ALLIGNORE)
4241      {
4242        SH_MUTEX_LOCK(mutex_thread_nolog);
4243        sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, ENOENT, 
4244                         MSG_FI_NOGRP,
4245                         (long) buf.st_gid, tmp2);
4246        SH_MUTEX_UNLOCK(mutex_thread_nolog);
4247      }
4248    else
4249      {
4250        SH_MUTEX_LOCK(mutex_thread_nolog);
4251        sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, ENOENT, 
4252                         MSG_FI_NOGRP,
4253                         (long) buf.st_gid, tmp2);
4254        SH_MUTEX_UNLOCK(mutex_thread_nolog);
4255      }
4256    SH_FREE(tmp2);
4257    sl_snprintf(theFile->c_group, GROUP_MAX+1, "%d", (long) buf.st_gid); 
4258  }
4259
4260 
4261  if (NULL == sh_unix_getUIDname(SH_ERR_ALL, buf.st_uid, theFile->c_owner, USER_MAX+1)) {
4262
4263    tmp2 = sh_util_safe_name (theFile->fullpath);
4264
4265    if (policy == SH_LEVEL_ALLIGNORE)
4266      {
4267        SH_MUTEX_LOCK(mutex_thread_nolog);
4268        sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, ENOENT, 
4269                         MSG_FI_NOUSR,
4270                         (long) buf.st_uid, tmp2);
4271        SH_MUTEX_UNLOCK(mutex_thread_nolog);
4272      }
4273    else
4274      {
4275        SH_MUTEX_LOCK(mutex_thread_nolog);
4276        sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, ENOENT, 
4277                         MSG_FI_NOUSR,
4278                         (long) buf.st_uid, tmp2);
4279        SH_MUTEX_UNLOCK(mutex_thread_nolog);
4280      }
4281    SH_FREE(tmp2);
4282    sl_snprintf(theFile->c_owner, USER_MAX+1, "%d", (long) buf.st_uid); 
4283  }
4284
4285  /* --- Output the file. ---
4286   */
4287  if (flag_err_debug == S_TRUE)
4288    {
4289      tmp2 = sh_util_safe_name ((filename == NULL) ? 
4290                                theFile->fullpath : filename);
4291      (void) sh_unix_time(theFile->mtime, timestr, sizeof(timestr));
4292      SH_MUTEX_LOCK(mutex_thread_nolog);
4293      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_LIST,
4294                       theFile->c_mode,
4295                       theFile->hardlinks,
4296                       theFile->c_owner,
4297                       theFile->c_group,
4298                       (unsigned long) theFile->size,
4299                       timestr,
4300                       tmp2);
4301      SH_MUTEX_UNLOCK(mutex_thread_nolog);
4302      SH_FREE(tmp2);
4303    }
4304
4305  /* --- Check for links. ---
4306   */
4307  if (theFile->c_mode[0] == 'l') 
4308    {
4309      linknamebuf = SH_ALLOC(PATH_MAX);
4310
4311      /* flawfinder: ignore */
4312      linksize    = readlink (theFile->fullpath, linknamebuf, PATH_MAX-1);
4313
4314      if (linksize < (PATH_MAX-1) && linksize >= 0) 
4315        linknamebuf[linksize] = '\0';
4316      else 
4317        linknamebuf[PATH_MAX-1] = '\0';
4318     
4319      if (linksize < 0) 
4320        {
4321          char errbuf[SH_ERRBUF_SIZE];
4322          linksize = errno;
4323          tmp2 = sh_util_safe_name (theFile->fullpath);
4324          SH_MUTEX_LOCK(mutex_thread_nolog);
4325          sh_error_handle (level, FIL__, __LINE__, linksize, MSG_FI_RDLNK,
4326                           sh_error_message (linksize, errbuf, sizeof(errbuf)), tmp2);
4327          SH_MUTEX_UNLOCK(mutex_thread_nolog);
4328          SH_FREE(tmp2);
4329          SH_FREE(linknamebuf);
4330          theFile->link_path = sh_util_strdup("-");
4331          SL_RETURN((-1),_("sh_unix_getinfo"));
4332        }
4333
4334      if (linknamebuf[0] == '/') 
4335        {
4336          theFile->link_path = sh_util_strdup (linknamebuf);
4337        } 
4338      else 
4339        {
4340          tmp = sh_util_dirname(theFile->fullpath);
4341          if (tmp) {
4342            theFile->link_path = SH_ALLOC(PATH_MAX);
4343            sl_strlcpy (theFile->link_path, tmp, PATH_MAX);
4344            SH_FREE(tmp);
4345          } else {
4346            theFile->link_path = SH_ALLOC(PATH_MAX);
4347            theFile->link_path[0] = '\0';
4348          }
4349          /*
4350           * Only attach '/' if not root directory. Handle "//", which
4351           * according to POSIX is implementation-defined, and may be
4352           * different from "/" (however, three or more '/' will collapse
4353           * to one).
4354           */
4355          tmp = theFile->link_path; while (*tmp == '/') ++tmp;
4356          if (*tmp != '\0')
4357            {
4358              sl_strlcat (theFile->link_path, "/", PATH_MAX);
4359            }
4360          sl_strlcat (theFile->link_path, linknamebuf, PATH_MAX);
4361        }
4362     
4363      /* stat the link
4364       */
4365      stat_return = retry_lstat (FIL__, __LINE__, theFile->link_path, &lbuf); 
4366     
4367      /* check for error
4368       */
4369      if (stat_return != 0) 
4370        { 
4371          stat_return = errno;
4372          tmp  = sh_util_safe_name (theFile->fullpath);
4373          tmp2 = sh_util_safe_name (theFile->link_path);
4374          if (stat_return != ENOENT)
4375            { 
4376              uid_t euid;
4377              char errbuf[SH_ERRBUF_SIZE];
4378
4379              (void) sl_get_euid(&euid);
4380              SH_MUTEX_LOCK(mutex_thread_nolog);
4381              sh_error_handle (level, FIL__, __LINE__, stat_return, 
4382                               MSG_FI_STAT,
4383                               _("lstat (link target)"),
4384                               sh_error_message (stat_return,errbuf, sizeof(errbuf)), 
4385                               (long) euid,
4386                               tmp2);
4387              SH_MUTEX_UNLOCK(mutex_thread_nolog);
4388            }
4389          else 
4390            {
4391              /* a dangling link -- everybody seems to have plenty of them
4392               */
4393              SH_MUTEX_LOCK(mutex_thread_nolog);
4394              sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DLNK,
4395                               tmp, tmp2);
4396              SH_MUTEX_UNLOCK(mutex_thread_nolog);
4397            }
4398          theFile->linkisok = BAD;
4399          SH_FREE(tmp);
4400          SH_FREE(tmp2);
4401          SH_FREE(linknamebuf);
4402          /*
4403           * changed Tue Feb 10 16:16:13 CET 2004:
4404           *  add dangling symlinks into database
4405           * SL_RETURN((-1),_("sh_unix_getinfo"));
4406           */
4407          theFile->linkmode = 0;
4408          SL_RETURN((0),_("sh_unix_getinfo")); 
4409        }
4410     
4411      theFile->linkisok = GOOD;
4412     
4413     
4414      /* --- Determine file type. ---
4415       */
4416      sh_unix_getinfo_type (&lbuf, &type, theFile->link_c_mode);
4417      theFile->type = type;
4418     
4419      /* --- Determine permissions. ---
4420       */
4421      sh_unix_getinfo_mode (&lbuf, &mode, theFile->link_c_mode);
4422      theFile->linkmode = lbuf.st_mode;
4423     
4424      /* --- Output the link. ---
4425       */
4426      if (theFile->linkisok == GOOD) 
4427        {
4428          tmp2 = sh_util_safe_name (linknamebuf);     
4429          SH_MUTEX_LOCK(mutex_thread_nolog);
4430          sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_LLNK,
4431                           theFile->link_c_mode, tmp2);
4432          SH_MUTEX_UNLOCK(mutex_thread_nolog);
4433          SH_FREE(tmp2);
4434        }
4435      SH_FREE(linknamebuf);
4436    }
4437  else /* not a link, theFile->c_mode[0] != 'l' */
4438    {
4439      if (content)
4440        {
4441#ifdef HAVE_LIBZ
4442          unsigned long   clen;
4443          unsigned char * compressed;
4444#ifdef HAVE_COMPRESSBOUND
4445          clen       = compressBound(sh_string_len(content));
4446#else
4447          if (sh_string_len(content) > 10*SH_TXT_MAX)
4448            clen = SH_TXT_MAX;
4449          else
4450            clen = 13 + (int)(1.0001*sh_string_len(content));
4451#endif
4452          compressed = SH_ALLOC(clen);
4453          if (Z_OK == compress(compressed, &clen, 
4454                               (unsigned char *) sh_string_str(content), 
4455                               sh_string_len(content)))
4456              {
4457                if (clen < SH_TXT_MAX)
4458                  {
4459                    sh_util_base64_enc_alloc (&(theFile->link_path), 
4460                                              (char *) compressed, clen);
4461                  }
4462                else
4463                  {
4464                    char tmsg[128];
4465                    char * tpath = sh_util_safe_name (theFile->fullpath);
4466                    sl_snprintf(tmsg, sizeof(tmsg), 
4467                                _("compressed file too large (%lu bytes)"),
4468                                clen);
4469                    SH_MUTEX_LOCK(mutex_thread_nolog);
4470                    sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, -1, 
4471                                     MSG_E_SUBGPATH, tmsg, 
4472                                     _("sh_unix_getinfo"), tpath);
4473                    SH_MUTEX_UNLOCK(mutex_thread_nolog);
4474                    SH_FREE(tpath);
4475                  }
4476              }
4477          SH_FREE(compressed);
4478#endif
4479          sh_string_destroy(&content);
4480        }
4481    } 
4482  SL_RETURN((0),_("sh_unix_getinfo"));
4483}
4484
4485/*  #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)  */
4486#endif
4487
4488int sh_unix_unlock(char * lockfile, char * flag)
4489{
4490  int         error = 0;
4491 
4492  SL_ENTER(_("sh_unix_unlock"));
4493
4494  if (sh.flag.isdaemon == S_FALSE && flag == NULL)
4495    SL_RETURN((0),_("sh_unix_unlock"));
4496
4497  /* --- Logfile is not locked to us. ---
4498   */
4499  if (sh.flag.islocked == BAD && flag != NULL) 
4500    SL_RETURN((-1),_("sh_unix_unlock"));
4501
4502  /* --- Check whether the directory is secure. ---
4503   */
4504  if (0 != tf_trust_check (lockfile, SL_YESPRIV))
4505    SL_RETURN((-1),_("sh_unix_unlock"));
4506
4507  /* --- Delete the lock file. ---
4508   */
4509  error = retry_aud_unlink (FIL__, __LINE__, lockfile);
4510 
4511  if (error == 0)
4512    {
4513      if (flag != NULL)
4514        sh.flag.islocked = BAD; /* not locked anymore */
4515    }
4516  else if (flag != NULL)
4517    {
4518      char errbuf[SH_ERRBUF_SIZE];
4519      error = errno;
4520      sh_error_handle ((-1), FIL__, __LINE__, error, MSG_E_UNLNK,
4521                       sh_error_message(error, errbuf, sizeof(errbuf)), 
4522                       lockfile);
4523      SL_RETURN((-1),_("sh_unix_unlock"));
4524    }
4525  SL_RETURN((0),_("sh_unix_unlock"));
4526}
4527
4528int sh_unix_check_piddir (char * pidpath)
4529{
4530  static        struct stat   buf;
4531  int           status = 0;
4532  char        * pid_dir;
4533 
4534  SL_ENTER(_("sh_unix_check_piddir"));
4535
4536  pid_dir = sh_util_dirname (pidpath);
4537
4538  status = retry_lstat (FIL__, __LINE__, pid_dir, &buf);
4539
4540  if (status < 0 && errno == ENOENT)
4541    {
4542      status = mkdir (pid_dir, 0777);
4543      if (status < 0)
4544        {
4545          sh_error_handle ((-1), FIL__, __LINE__, status,
4546                           MSG_E_SUBGEN, 
4547                           _("Cannot create PID directory"),
4548                           _("sh_unix_check_piddir"));
4549          SH_FREE(pid_dir);
4550          SL_RETURN((-1),_("sh_unix_check_piddir"));
4551        }
4552    }
4553  else if (!S_ISDIR(buf.st_mode))
4554    {
4555      sh_error_handle ((-1), FIL__, __LINE__, status,
4556                       MSG_E_SUBGEN, 
4557                       _("Path of PID directory refers to a non-directory object"),
4558                       _("sh_unix_check_piddir"));
4559      SH_FREE(pid_dir);
4560      SL_RETURN((-1),_("sh_unix_check_piddir"));
4561    }
4562  SH_FREE(pid_dir);
4563  SL_RETURN((0),_("sh_unix_check_piddir"));
4564}
4565
4566int sh_unix_lock (char * lockfile, char * flag)
4567{
4568  int filed;
4569  int errnum;
4570  char myPid[64];
4571  SL_TICKET  fd;
4572  extern int get_the_fd (SL_TICKET ticket);
4573
4574  SL_ENTER(_("sh_unix_lock"));
4575
4576  sprintf (myPid, "%ld\n", (long) sh.pid);             /* known to fit  */
4577
4578  if (flag == NULL) /* PID file, check for directory */
4579    {
4580      if (0 != sh_unix_check_piddir (lockfile))
4581        {
4582          SL_RETURN((-1),_("sh_unix_lock"));
4583        }
4584    }
4585
4586  fd = sl_open_safe_rdwr (FIL__, __LINE__, 
4587                          lockfile, SL_YESPRIV);      /* fails if file exists */
4588
4589  if (!SL_ISERROR(fd))
4590    {
4591      errnum = sl_write (fd, myPid, sl_strlen(myPid));
4592      filed = get_the_fd(fd);
4593      fchmod (filed, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
4594      sl_close (fd);
4595
4596      if (!SL_ISERROR(errnum))
4597        {
4598          if (flag != NULL)
4599            sh.flag.islocked = GOOD;
4600          SL_RETURN((0),_("sh_unix_lock"));
4601        }
4602    }
4603
4604  TPT((0, FIL__, __LINE__, _("msg=<open pid file failed>\n")));
4605  if (flag != NULL)
4606    sh.flag.islocked       = BAD;
4607  SL_RETURN((-1),_("sh_unix_lock"));
4608
4609  /* notreached */
4610}
4611
4612
4613/* check whether file is locked
4614 */
4615int sh_unix_test_and_lock (char * filename, char * lockfile)
4616{
4617  static        struct stat   buf;
4618  int           status = 0;
4619
4620
4621  SL_TICKET     fd;
4622  char          line_in[128];
4623
4624  SL_ENTER(_("sh_unix_test_and_lock"));
4625
4626  status = retry_lstat (FIL__, __LINE__, lockfile, &buf);
4627
4628  /* --- No lock file found, try to lock. ---
4629   */
4630
4631  if (status < 0 && errno == ENOENT)
4632    {
4633      if (0 == sh_unix_lock (lockfile, filename))
4634        { 
4635          if (filename != NULL) 
4636            sh.flag.islocked = GOOD;
4637          SL_RETURN((0),_("sh_unix_test_and_lock"));
4638        }
4639      else
4640        {
4641          sh_error_handle ((-1), FIL__, __LINE__, status,
4642                           MSG_E_SUBGEN, 
4643                           (filename == NULL) ? _("Cannot create PID file (1)") : _("Cannot create lock file (1)"),
4644                           _("sh_unix_test_and_lock"));
4645          SL_RETURN((-1),_("sh_unix_test_and_lock"));
4646        }
4647    }
4648  else if (status == 0 && buf.st_size == 0)
4649    {
4650      if (filename != NULL)
4651        sh.flag.islocked = GOOD;
4652      sh_unix_unlock (lockfile, filename);
4653      if (filename != NULL)
4654        sh.flag.islocked = BAD;
4655      if (0 == sh_unix_lock (lockfile, filename))
4656        { 
4657          if (filename != NULL)
4658            sh.flag.islocked = GOOD;
4659          SL_RETURN((0),_("sh_unix_test_and_lock"));
4660        }
4661      else
4662        {
4663          sh_error_handle ((-1), FIL__, __LINE__, status,
4664                           MSG_E_SUBGEN, 
4665                           (filename == NULL) ? _("Cannot create PID file (2)") : _("Cannot create lock file (2)"),
4666                           _("sh_unix_test_and_lock"));
4667          SL_RETURN((-1),_("sh_unix_test_and_lock"));
4668        }
4669    }
4670
4671  /* --- Check on lock. ---
4672   */
4673 
4674  if (status >= 0)
4675    {
4676       fd = sl_open_read (FIL__, __LINE__, lockfile, SL_YESPRIV);
4677       if (SL_ISERROR(fd))
4678         sh_error_handle ((-1), FIL__, __LINE__, fd,
4679                          MSG_E_SUBGEN, 
4680                          (filename == NULL) ? _("Cannot open PID file for read") : _("Cannot open lock file for read"),
4681                          _("sh_unix_test_and_lock"));
4682    }
4683  else
4684    fd = -1;
4685
4686  if (!SL_ISERROR(fd))
4687    {
4688      /* read the PID in the lock file
4689       */
4690      status = sl_read (fd, line_in, sizeof(line_in));
4691      line_in[sizeof(line_in)-1] = '\0';
4692
4693      /* convert to numeric
4694       */
4695      if (status > 0)
4696        {
4697          errno  = 0;
4698          status = strtol(line_in, (char **)NULL, 10);
4699          if (errno == ERANGE || status <= 0)
4700             {
4701                sh_error_handle ((-1), FIL__, __LINE__, status,
4702                                 MSG_E_SUBGEN, 
4703                                 (filename == NULL) ? _("Bad PID in PID file") : _("Bad PID in lock file"),
4704                                 _("sh_unix_test_and_lock"));
4705
4706                status = -1;
4707             }
4708        }
4709      else
4710        {
4711           sh_error_handle ((-1), FIL__, __LINE__, status,
4712                            MSG_E_SUBGEN, 
4713                            (filename == NULL) ? _("Cannot read PID file") : _("Cannot read lock file"),
4714                            _("sh_unix_test_and_lock"));
4715        }
4716      sl_close(fd);
4717
4718      if (status > 0 && (unsigned int) status == sh.pid)
4719        {
4720          if (filename != NULL)
4721            sh.flag.islocked = GOOD;
4722          SL_RETURN((0),_("sh_unix_test_and_lock"));
4723        }
4724
4725
4726      /* --- Check whether the process exists. ---
4727       */
4728      if (status > 0)
4729        {
4730          errno  = 0;
4731          status = aud_kill (FIL__, __LINE__, status, 0);
4732
4733          /* Does not exist, so remove the stale lock
4734           * and create a new one.
4735           */
4736          if (status < 0 && errno == ESRCH)
4737            {
4738              if (filename != NULL)
4739                sh.flag.islocked = GOOD;
4740              if (0 != sh_unix_unlock(lockfile, filename) && (filename !=NULL))
4741                sh.flag.islocked = BAD;
4742              else
4743                {
4744                  if (0 == sh_unix_lock  (lockfile, filename))
4745                    {
4746                      if (filename != NULL)
4747                        sh.flag.islocked = GOOD;
4748                      SL_RETURN((0),_("sh_unix_test_and_lock"));
4749                    }
4750                   else
4751                    {
4752                       sh_error_handle ((-1), FIL__, __LINE__, status,
4753                                        MSG_E_SUBGEN, 
4754                                        (filename == NULL) ? _("Cannot create PID file (3)") : _("Cannot create lock file (3)"),
4755                                        _("sh_unix_test_and_lock"));
4756                    }
4757                  if (filename != NULL)
4758                    sh.flag.islocked = BAD;
4759                }
4760            }
4761          else
4762            {
4763              sh_error_handle ((-1), FIL__, __LINE__, status,
4764                               MSG_E_SUBGEN, 
4765                               (filename == NULL) ? _("Cannot remove stale PID file, PID may be a running process") : _("Cannot remove stale lock file, PID may be a running process"),
4766                               _("sh_unix_test_and_lock"));
4767              if (filename != NULL)
4768                sh.flag.islocked = BAD;
4769            }
4770        }
4771    }
4772  SL_RETURN((-1),_("sh_unix_testlock"));
4773}
4774
4775/* write the PID file
4776 */
4777int sh_unix_write_pid_file()
4778{
4779  return sh_unix_test_and_lock(NULL, sh.srvlog.alt);
4780}
4781
4782/* write lock for filename
4783 */
4784int sh_unix_write_lock_file(char * filename)
4785{
4786  size_t len;
4787  int    res;
4788  char * lockfile;
4789
4790  if (filename == NULL)
4791    return (-1);
4792
4793  len = sl_strlen(filename);
4794  if (sl_ok_adds(len, 6))
4795    len += 6;
4796  lockfile = SH_ALLOC(len);
4797  sl_strlcpy(lockfile, filename,   len);
4798  sl_strlcat(lockfile, _(".lock"), len);
4799  res = sh_unix_test_and_lock(filename, lockfile);
4800  SH_FREE(lockfile);
4801  return res;
4802}
4803
4804/* rm lock for filename
4805 */
4806int sh_unix_rm_lock_file(char * filename)
4807{
4808  size_t len;
4809  int res;
4810  char * lockfile;
4811
4812  if (filename == NULL)
4813    return (-1);
4814
4815  len = sl_strlen(filename);
4816  if (sl_ok_adds(len, 6))
4817    len += 6;
4818  lockfile = SH_ALLOC(len);
4819  sl_strlcpy(lockfile, filename,   len);
4820  sl_strlcat(lockfile, _(".lock"), len);
4821
4822  res = sh_unix_unlock(lockfile, filename);
4823  SH_FREE(lockfile);
4824  return res;
4825}
4826
4827/* rm lock for filename
4828 */
4829int sh_unix_rm_pid_file()
4830{
4831  return sh_unix_unlock(sh.srvlog.alt, NULL);
4832}
4833
4834/* Test whether file exists
4835 */
4836int sh_unix_file_exists(char * path)
4837{
4838  struct stat buf;
4839
4840  SL_ENTER(_("sh_unix_file_exists"));
4841
4842  if (0 == retry_lstat(FIL__, __LINE__, path, &buf))
4843    SL_RETURN( S_TRUE,   _("sh_unix_file_exists"));
4844  else 
4845    SL_RETURN( S_FALSE,  _("sh_unix_file_exists"));
4846}
4847
4848
4849/* Test whether file exists, is a character device, and allows read
4850 * access.
4851 */
4852int sh_unix_device_readable(int fd)
4853{
4854  struct stat buf;
4855
4856  SL_ENTER(_("sh_unix_device_readable"));
4857
4858  if (retry_fstat(FIL__, __LINE__, fd, &buf) == -1)
4859    SL_RETURN( (-1), _("sh_unix_device_readable"));
4860  else if ( S_ISCHR(buf.st_mode) &&  0 != (S_IROTH & buf.st_mode) ) 
4861    SL_RETURN( (0), _("sh_unix_device_readable"));
4862  else 
4863    SL_RETURN( (-1), _("sh_unix_device_readable"));
4864}
4865
4866static char preq[16];
4867
4868/* return true if database is remote
4869 */
4870int file_is_remote ()
4871{
4872  static int init = 0;
4873  struct stat buf;
4874
4875  SL_ENTER(_("file_is_remote"));
4876
4877  if (init == 0)
4878    {
4879      sl_strlcpy(preq, _("REQ_FROM_SERVER"), 16);
4880      ++init;
4881    }
4882  if (0 == sl_strncmp (sh.data.path, preq, 15))
4883    {
4884      if (sh.data.path[15] != '\0') /* should be start of path */
4885        {
4886          if (0 == stat(&(sh.data.path[15]), &buf))
4887            {
4888              SL_RETURN( S_FALSE, _("file_is_remote"));
4889            }
4890          else
4891            {
4892              char * tmp  = sh_util_safe_name (&(sh.data.path[15]));
4893              sh_error_handle((-1), FIL__, __LINE__, S_FALSE, MSG_E_SUBGPATH, 
4894                              _("No local baseline database at expected path"), 
4895                              _("file_is_remote"),
4896                              tmp);
4897              SH_FREE(tmp);
4898            }
4899        }
4900      else
4901        {
4902          sh_error_handle((-1), FIL__, __LINE__, S_FALSE, MSG_E_SUBGEN, 
4903                          _("No local baseline database path known"), 
4904                          _("file_is_remote"));
4905        }
4906      SL_RETURN( S_TRUE, _("file_is_remote"));
4907    }
4908  SL_RETURN( S_FALSE, _("file_is_remote"));
4909}
4910
4911/* Return the path to the configuration/database file.
4912 */
4913char * file_path(char what, char flag)
4914{
4915  static int init = 0;
4916
4917  SL_ENTER(_("file_path"));
4918
4919  if (init == 0)
4920    {
4921      sl_strlcpy(preq, _("REQ_FROM_SERVER"), 16);
4922      ++init;
4923    }
4924
4925  switch (what)
4926    {
4927
4928    case 'C':
4929      if (0 == sl_strncmp (sh.conf.path, preq, 15))
4930        {
4931#if defined(SH_WITH_SERVER)
4932          if (sh.flag.isserver == S_TRUE && sl_strlen(sh.conf.path) == 15)
4933            SL_RETURN( NULL, _("file_path"));
4934          if (sh.flag.isserver == S_TRUE)
4935            SL_RETURN( &(sh.conf.path[15]), _("file_path"));
4936#endif
4937          if (flag == 'R')
4938            SL_RETURN( preq, _("file_path"));
4939          if (flag == 'I')
4940            {
4941              if (sl_strlen(sh.conf.path) == 15)
4942                SL_RETURN( NULL, _("file_path"));
4943              else
4944                SL_RETURN( &(sh.conf.path[15]), _("file_path"));
4945            }
4946          SL_RETURN ( preq, _("file_path"));
4947        }
4948      else
4949        SL_RETURN( sh.conf.path, _("file_path"));
4950      /* break; *//* unreachable */
4951
4952    case 'D':
4953      if (0 == sl_strncmp (sh.data.path, preq, 15))
4954        {
4955          if (flag == 'R')
4956            SL_RETURN( preq, _("file_path"));
4957          if (flag == 'W' && sl_strlen(sh.data.path) == 15)
4958            SL_RETURN (NULL, _("file_path"));
4959          if (flag == 'W')
4960            SL_RETURN( &(sh.data.path[15]), _("file_path"));
4961        }
4962      else
4963        SL_RETURN( sh.data.path, _("file_path"));
4964      break;
4965       
4966    default:
4967      SL_RETURN( NULL, _("file_path"));
4968    }
4969
4970  return NULL; /* notreached */
4971}
4972/************************************************/
4973/****   Mlock   Utilities                    ****/
4974/************************************************/
4975
4976#include <limits.h>
4977
4978int sh_unix_pagesize()
4979{
4980  int pagesize = 4096;
4981#if defined(_SC_PAGESIZE)
4982  pagesize = sysconf(_SC_PAGESIZE);
4983#elif defined(_SC_PAGE_SIZE)
4984  pagesize = sysconf(_SC_PAGE_SIZE);
4985#elif defined(HAVE_GETPAGESIZE)
4986  pagesize = getpagesize();
4987#elif defined(PAGESIZE)
4988  pagesize = PAGESIZE;
4989#endif
4990 
4991  return ((pagesize > 0) ? pagesize : 4096);
4992}
4993
4994typedef struct sh_page_lt {
4995  unsigned long  page_start;
4996  int            page_refcount;
4997  char           file[64];
4998  int            line;
4999  struct sh_page_lt * next;
5000} sh_page_l;
5001
5002sh_page_l * sh_page_locked = NULL;
5003volatile int page_locking = 0;
5004
5005unsigned long sh_unix_lookup_page (void * in_addr, size_t len, int * num_pages)
5006{
5007  int pagesize = sh_unix_pagesize();
5008  unsigned long  addr = (unsigned long) in_addr;
5009
5010  unsigned long pagebase;
5011  unsigned long pagediff;
5012  unsigned long pagenum   = addr / pagesize;
5013
5014  SL_ENTER(_("sh_unix_lookup_page"));
5015#if 0
5016  fprintf(stderr, "mlock: --> base %ld, pagenum: %ld\n",
5017          addr, pagenum);
5018#endif
5019
5020  /* address of first page
5021   */
5022  pagebase = pagenum * pagesize;
5023 
5024  /* number of pages
5025   */
5026  pagediff = (addr + len) - pagebase;
5027  pagenum  = pagediff / pagesize;
5028  if (pagenum * pagesize < pagediff)
5029    ++pagenum;
5030
5031#if 0
5032  fprintf(stderr, "mlock: --> pagebase %ld, pagediff %ld, (addr + len) %ld\n",
5033          pagebase, pagediff, (addr + len));
5034#endif
5035
5036  *num_pages = pagenum;
5037  SL_RETURN((pagebase), _("sh_unix_lookup_page"));
5038}
5039
5040
5041#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
5042
5043SH_MUTEX_STATIC(mutex_mlock,PTHREAD_MUTEX_INITIALIZER);
5044
5045int sh_unix_mlock (const char * file, int line, void * in_addr, size_t len)
5046{
5047  int         num_pages;
5048  int         status = 0;
5049  int         pagesize;
5050  sh_page_l * page_list;
5051  unsigned long addr;
5052#ifdef TEST_MLOCK
5053  int         i = 0;
5054#endif
5055
5056  SL_ENTER(_("sh_unix_mlock"));
5057
5058  /* There's no cancellation point here, except if tracing is on
5059   */
5060  SH_MUTEX_LOCK_UNSAFE(mutex_mlock);
5061
5062  page_list = sh_page_locked;
5063
5064  if (0 != page_locking)
5065    {
5066      status = -1;
5067      goto exit_mlock;
5068    }
5069
5070  page_locking = 1;
5071
5072  pagesize = sh_unix_pagesize();
5073  addr = sh_unix_lookup_page (in_addr, len, &num_pages);
5074
5075#ifdef TEST_MLOCK
5076  fprintf(stderr, "mlock: addr %ld, base %ld, pages: %d, length %d\n", 
5077          (unsigned long) in_addr, addr, num_pages, len);
5078#endif
5079
5080  /* increase refcount of locked pages
5081   * addr is first page; num_pages is #(consecutive pages) to lock
5082   */
5083
5084  while ((page_list != NULL) && (num_pages > 0))
5085    {
5086#ifdef TEST_MLOCK
5087      fprintf(stderr, "mlock: check page %d: %ld [%d]\n", 
5088              i, page_list->page_start, page_list->page_refcount);
5089#endif
5090      if (page_list->page_start == addr)
5091        {
5092          page_list->page_refcount += 1;
5093          num_pages -= 1;
5094          addr += pagesize;
5095#ifdef TEST_MLOCK
5096          fprintf(stderr, "mlock: found page %d: %ld [%d], next page %ld\n", 
5097                  i, page_list->page_start, page_list->page_refcount, addr);
5098#endif
5099        }
5100#ifdef TEST_MLOCK
5101      ++i;
5102#endif
5103      page_list = page_list->next;
5104    }
5105
5106  /* mlock some more pages, if needed
5107   */
5108  while (num_pages > 0) 
5109    {
5110#ifdef TEST_MLOCK
5111      fprintf(stderr, "mlock: lock  page %d: mlock %ld [num_pages %d]\n", 
5112              i, addr, num_pages);
5113      ++i;
5114#endif
5115      page_list = SH_ALLOC(sizeof(sh_page_l));
5116      page_list->page_start = addr;
5117      page_list->page_refcount = 1;
5118      sl_strlcpy(page_list->file, file, 64);
5119      page_list->line = line;
5120      status = mlock( (void *) addr, pagesize);
5121      if (status != 0)
5122        {
5123#ifdef TEST_MLOCK
5124          char errbuf[SH_ERRBUF_SIZE];
5125          fprintf(stderr, "mlock: error: %s\n", 
5126                  sh_error_message(errno, errbuf, sizeof(errbuf)));
5127#endif
5128          SH_FREE(page_list);
5129          page_locking = 0;
5130          goto exit_mlock;
5131        }
5132      page_list->next = sh_page_locked;
5133      sh_page_locked  = page_list;
5134      num_pages -= 1;
5135      addr += pagesize;
5136    }
5137  page_locking = 0;
5138
5139 exit_mlock:
5140  SH_MUTEX_UNLOCK_UNSAFE(mutex_mlock);
5141
5142  SL_RETURN((status), _("sh_unix_mlock"));
5143}
5144#else
5145int sh_unix_mlock (const char * file, int line, void * in_addr, size_t len)
5146{
5147  (void) file;    (void) line;
5148  (void) in_addr; (void) len;
5149  return -1;
5150}
5151#endif
5152
5153#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
5154int sh_unix_munlock (void * in_addr, size_t len)
5155{
5156  int         num_pages;
5157  int         unlocked;
5158  int         status;
5159  int         pagesize;
5160  sh_page_l * page_list;
5161  sh_page_l * page_last;
5162  unsigned long addr;
5163
5164  int           test_count;
5165  int           test_status;
5166  int           test_pages;
5167
5168#ifdef TEST_MLOCK
5169  int         i = 0;
5170#endif
5171
5172  SL_ENTER(_("sh_unix_munlock"));
5173
5174  /* There's no cancellation point here, except if tracing is on
5175   */
5176  SH_MUTEX_LOCK_UNSAFE(mutex_mlock);
5177
5178  unlocked  = 0;
5179  status    = 0;
5180  page_list = sh_page_locked;
5181
5182  if (0 != page_locking)
5183    {
5184      status = -1;
5185      goto exit_munlock;
5186    }
5187  page_locking = 1;
5188
5189  pagesize = sh_unix_pagesize();
5190  addr     = sh_unix_lookup_page (in_addr, len, &num_pages);
5191
5192#ifdef TEST_MLOCK
5193  fprintf(stderr, "munlock: in_addr %ld, addr %ld, pages: %d, length %d\n", 
5194          (unsigned long) in_addr, addr, num_pages, len);
5195#endif
5196
5197  test_pages = num_pages;
5198
5199  /* reduce refcount of locked pages
5200   * addr is first page; num_pages is #(consecutive pages) to lock
5201   */
5202  while ((page_list != NULL) && (num_pages > 0))
5203    {
5204#ifdef TEST_MLOCK
5205      fprintf(stderr, "munlock: page %d: %ld [%d]\n", 
5206              i, page_list->page_start, page_list->page_refcount);
5207#endif
5208
5209      test_status = 0;
5210      for (test_count = 0; test_count < test_pages; ++test_count)
5211        {
5212          if (page_list->page_start == (addr + (test_count * pagesize)))
5213            {
5214              test_status = 1;
5215              break;
5216            }
5217        }
5218
5219      if (test_status == 1)
5220        {
5221          page_list->page_refcount -= 1;
5222          if (page_list->page_refcount == 0)
5223            {
5224              status = munlock ( (void *) addr, pagesize);
5225              ++unlocked;
5226            }
5227          num_pages -= 1;
5228#ifdef TEST_MLOCK
5229          fprintf(stderr, 
5230                  "munlock: page %d: %ld [refcount %d], refcount reduced\n", 
5231                  i, page_list->page_start, page_list->page_refcount);
5232#endif
5233        }
5234#ifdef TEST_MLOCK
5235      ++i;
5236#endif
5237      page_list = page_list->next;
5238    }
5239
5240#ifdef TEST_MLOCK
5241      i = 0;
5242#endif
5243
5244  if (unlocked > 0)
5245    {
5246      page_list = sh_page_locked;
5247      page_last = sh_page_locked;
5248
5249      while ((page_list != NULL) && (unlocked > 0))
5250        {
5251          if (page_list->page_refcount == 0)
5252            {
5253#ifdef TEST_MLOCK
5254              fprintf(stderr, "munlock: remove page %d: %ld [refcount %d]\n", 
5255                      i, page_list->page_start, page_list->page_refcount);
5256#endif
5257              if (page_last != page_list)
5258                {
5259                  page_last->next = page_list->next;
5260                  SH_FREE(page_list);
5261                  page_list = page_last->next;
5262                }
5263              else
5264                {
5265                  page_last = page_list->next;
5266                  if (page_list == sh_page_locked)
5267                    sh_page_locked = page_list->next;
5268                  SH_FREE(page_list);
5269                  page_list = page_last;
5270                }
5271              --unlocked;
5272            }
5273          else
5274            {
5275#ifdef TEST_MLOCK
5276              fprintf(stderr, "munlock: skip   page %d: %ld [refcount %d]\n", 
5277                      i, page_list->page_start, page_list->page_refcount);
5278#endif
5279
5280              page_last = page_list;
5281              page_list = page_list->next;
5282            }
5283#ifdef TEST_MLOCK
5284          ++i;
5285#endif
5286        }
5287    }
5288
5289  page_locking = 0;
5290
5291 exit_munlock:
5292  SH_MUTEX_UNLOCK_UNSAFE(mutex_mlock);
5293  SL_RETURN((status), _("sh_unix_munlock"));
5294}
5295#else
5296int sh_unix_munlock (void * in_addr, size_t len)
5297{
5298  (void) in_addr; (void) len;
5299  return -1;
5300}
5301#endif
5302
5303int sh_unix_count_mlock()
5304{
5305  unsigned int i = 0;
5306  char str[32][64];
5307  sh_page_l * page_list;
5308
5309  SL_ENTER(_("sh_unix_count_mlock"));
5310
5311#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
5312  /* There's no cancellation point here, except if tracing is on
5313   */
5314  SH_MUTEX_LOCK_UNSAFE(mutex_mlock);
5315#endif
5316
5317  page_list = sh_page_locked;
5318
5319  while (page_list != NULL)
5320    {
5321#ifdef WITH_TPT
5322      if (i < 32)
5323        sl_snprintf(str[i], 64, _("file: %s line: %d page: %d"), 
5324                    page_list->file, page_list->line, i+1);
5325#endif
5326      page_list = page_list->next;
5327      ++i;
5328    }
5329
5330#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
5331  SH_MUTEX_UNLOCK_UNSAFE(mutex_mlock);
5332#endif
5333
5334#ifdef WITH_TPT
5335  {
5336    unsigned int j = 0;
5337    while (j < i && j < 32)
5338      {
5339        sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, j, MSG_E_SUBGEN,
5340                        str[j], _("sh_unix_count_mlock"));
5341        ++j;
5342      }
5343  }
5344#endif
5345
5346  sl_snprintf(str[0], 64, _("%d pages locked"), i);
5347  sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, i, MSG_E_SUBGEN,
5348                  str[0], _("sh_unix_count_mlock"));
5349  SL_RETURN((i), _("sh_unix_count_mlock"));
5350}
5351
5352/************************************************/
5353/************************************************/
5354/****   Stealth Utilities                    ****/
5355/************************************************/
5356/************************************************/
5357#ifdef SH_STEALTH
5358
5359void sh_unix_xor_code (char * str, int len)
5360{
5361  register int i;
5362
5363  for (i = 0; i < len; ++i) str[i] ^= (char) XOR_CODE;
5364  return;
5365}
5366
5367#if  !defined(SH_STEALTH_MICRO)
5368
5369
5370int hideout_hex_block(SL_TICKET fd, unsigned char * str, int len,
5371                      unsigned long * bytes_read);
5372unsigned long first_hex_block(SL_TICKET fd, unsigned long * max);
5373
5374/*
5375 * --- Get hidden data from a block of hex data. ---
5376 */
5377int sh_unix_getline_stealth (SL_TICKET fd, char * str, int len)
5378{
5379  int                  add_off = 0, llen;
5380  static unsigned long off_data   = 0;
5381  static unsigned long max_data   = 0;
5382  static unsigned long bytes_read = 0;
5383  static int           stealth_init = BAD;
5384
5385  SL_ENTER(_("sh_unix_getline_stealth"));
5386
5387  if (str == NULL)
5388    {
5389      off_data   = 0;
5390      max_data   = 0;
5391      bytes_read = 0;
5392      stealth_init = BAD;
5393      SL_RETURN(0, _("sh_unix_getline_stealth"));
5394    }
5395
5396  /* --- Initialize. ---
5397   */
5398  if (stealth_init == BAD)
5399    {
5400      off_data = first_hex_block(fd, &max_data);
5401      if (off_data == 0)
5402        {
5403          dlog(1, FIL__, __LINE__, 
5404               _("The stealth config file does not contain any steganographically\nhidden data. This file must be an image file in _uncompressed_\npostscript format.\nTo hide data in it, use:\n   samhain_stealth -s postscript_file orig_config_file\n   mv postscript_file /path/to/config/file\n"));
5405          sh_error_handle ((-1), FIL__, __LINE__,  EIO, MSG_P_NODATA,
5406                           _("Stealth config file."));
5407          aud_exit (FIL__, __LINE__, EXIT_FAILURE);
5408        }
5409      stealth_init = GOOD;
5410      max_data += off_data;
5411    }
5412 
5413  /* --- Seek to proper position. ---
5414   */
5415  if (bytes_read >= max_data || add_off < 0)
5416    {
5417      dlog(1, FIL__, __LINE__, 
5418           _("The capacity of the container image file for the stealth config file seems to be too small. Your config file is likely truncated.\n"));
5419      sh_error_handle ((-1), FIL__, __LINE__,  EIO, MSG_P_NODATA,
5420                       _("Stealth config file."));
5421      aud_exit (FIL__, __LINE__, EXIT_FAILURE);
5422    }
5423  sl_seek(fd, off_data);
5424     
5425  /* --- Read one line. ---
5426   */
5427  add_off   = hideout_hex_block(fd, (unsigned char *) str, len, &bytes_read);
5428  off_data += add_off;
5429
5430  llen = sl_strlen(str);
5431  SL_RETURN(llen, _("sh_unix_getline_stealth"));
5432}
5433
5434int hideout_hex_block(SL_TICKET fd, unsigned char * str, int len, 
5435                      unsigned long * bytes_read)
5436{
5437
5438  register int  i, j, k;
5439  unsigned char c, e;
5440  register int  num;
5441  unsigned char mask[9] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
5442  unsigned long here   = 0;
5443  unsigned long retval = 0;
5444  unsigned long bread  = 0;
5445
5446  SL_ENTER(_("hideout_hex_block"));
5447
5448  ASSERT_RET((len > 1), _("len > 1"), (0));
5449
5450  --len;
5451
5452  i = 0;
5453  while (i < len)
5454    {
5455      for (j = 0; j < 8; ++j)
5456        {
5457
5458          /* --- Get a low byte, modify, read back. ---
5459           */
5460          for (k = 0; k < 2; ++k)
5461            {
5462              /* -- Skip whitespace. ---
5463               */
5464              c = ' ';
5465              do {
5466                do {
5467                  num = sl_read (fd, &c, 1);
5468                } while (num == 0 && errno == EINTR);
5469                if (num > 0)
5470                  ++here;
5471                else if (num == 0)
5472                  SL_RETURN((0), _("hideout_hex_block"));
5473                else 
5474                  SL_RETURN((-1), _("hideout_hex_block"));
5475              } while (c == '\n' || c == '\t' || c == '\r' || 
5476                       c == ' ');
5477            }
5478         
5479
5480          /* --- e is the value of the low byte. ---
5481           */
5482          e = (unsigned char) sh_util_hexchar( c );
5483          if ((e & mask[7]) != 0)  /* bit is set     */
5484            str[i] |= mask[j];
5485          else                     /* bit is not set */
5486            str[i] &= ~mask[j];
5487
5488          bread += 1;
5489        }
5490      if (str[i] == '\n') break;
5491      ++i;
5492    }
5493
5494  if (i != 0)
5495    str[i] = '\0';
5496  else
5497    str[i+1] = '\0'; /* keep newline and terminate */
5498  retval += here;
5499  *bytes_read += (bread/8);
5500
5501  SL_RETURN(retval, _("hideout_hex_block"));
5502}
5503
5504/* --- Get offset of first data block. ---
5505 */
5506unsigned long first_hex_block(SL_TICKET fd, unsigned long * max)
5507{
5508  unsigned int  i;
5509  long          num = 1;
5510  unsigned long lnum;
5511  char          c;
5512  int           nothex = 0;
5513  unsigned long retval = 0;
5514  unsigned int  this_line = 0;
5515  char          theline[SH_BUFSIZE];
5516
5517  SL_ENTER(_("first_hex_block"));
5518
5519  *max = 0;
5520
5521  while (1)
5522    {
5523      theline[0] = '\0';
5524      this_line  = 0;
5525      c          = '\0';
5526      while (c != '\n' && this_line < (sizeof(theline)-1))
5527        {
5528          do {
5529            num = sl_read (fd, &c, 1);
5530          } while (num == 0 && errno == EINTR);
5531          if (num > 0) 
5532            theline[this_line] = c;
5533          else           
5534            SL_RETURN((0), _("first_hex_block"));
5535          ++this_line;
5536        }
5537      theline[this_line] = '\0';
5538     
5539      /* not only 'newline' */ 
5540      if (this_line > 60)
5541        {
5542          nothex  = 0;
5543          i       = 0;
5544          while (nothex == 0 && i < (this_line-1))
5545            {
5546              if (! isxdigit((int)theline[i])) nothex = 1;
5547              ++i;
5548            }
5549          if (nothex == 1) retval += this_line;
5550        }
5551      else
5552        {
5553          nothex = 1;
5554          retval += this_line;
5555        }
5556
5557      if (nothex == 0)
5558        {
5559          *max = 0; 
5560          do {
5561            do {
5562              num = sl_read (fd, theline, SH_BUFSIZE);
5563            } while (num == 0 && errno == EINTR);
5564            if (num > 0)
5565              {
5566                lnum = (unsigned long) num;
5567                for (i = 0; i < lnum; ++i)
5568                  { 
5569                    c = theline[i];
5570                    if (c == '\n' || c == '\t' || c == '\r' || c == ' ') 
5571                      ;
5572                    else if (!isxdigit((int)c))
5573                      break;
5574                    else
5575                      *max += 1;
5576                  }
5577              }
5578          } while (num > 0);
5579
5580          *max /= 16;
5581          SL_RETURN((retval), _("first_hex_block"));
5582        }
5583
5584    }
5585  /* SL_RETURN((0), _("first_hex_block")); *//* unreachable */
5586}
5587
5588 /* if !defined(SH_STEALTH_MICRO) */
5589#endif
5590
5591 /* ifdef SH_STEALTH */
5592#endif
5593
5594/*
5595 * anti-debugger code
5596 */
5597#if defined(SCREW_IT_UP)
5598
5599#if defined(HAVE_PTHREAD)
5600
5601static pthread_key_t  gSigtrapVariables_key;
5602static pthread_once_t gSigtrapVariables_key_once = PTHREAD_ONCE_INIT;
5603
5604static inline void make_gSigtrapVariables_key()
5605{
5606    (void) pthread_key_create(&gSigtrapVariables_key, free);
5607}
5608
5609struct sh_sigtrap_variables * sh_sigtrap_variables_get()
5610{
5611  void * ptr;
5612
5613  (void) pthread_once(&gSigtrapVariables_key_once, make_gSigtrapVariables_key);
5614 
5615  ptr = pthread_getspecific(gSigtrapVariables_key);
5616  if (ptr == NULL) {
5617    ptr = calloc(1,sizeof(struct sh_sigtrap_variables));
5618    if (ptr == NULL) {
5619      return NULL;
5620    }
5621    (void) pthread_setspecific(gSigtrapVariables_key, ptr);
5622  }
5623
5624  return (struct sh_sigtrap_variables *) ptr;
5625}
5626
5627/* !defined(HAVE_PTHREAD) */
5628#else
5629
5630static struct sh_sigtrap_variables global_sigtrap_variables;
5631struct sh_sigtrap_variables * sh_sigtrap_variables_get()
5632{
5633  return &global_sigtrap_variables;
5634}
5635
5636#endif
5637
5638int sh_sigtrap_max_duration_set (const char * str)
5639{
5640  /* For security (prevent reloading with larger value)
5641   * this value can only be set once.
5642   */
5643  static int once = 0;
5644  int i;
5645
5646  SL_ENTER(_("sh_sigtrap_max_duration_set"));
5647
5648  i = atoi (str);
5649
5650  if (i >= 0 && once == 0)
5651    {
5652      sh.sigtrap_max_duration = i;
5653      once = 1;
5654    }
5655  else
5656    {
5657      SL_RETURN ((-1), _("sh_sigtrap_max_duration_set"));
5658    }
5659  SL_RETURN( (0), _("sh_sigtrap_max_duration_set"));
5660}
5661
5662void sh_sigtrap_handler (int signum)
5663{
5664  struct sh_sigtrap_variables * sigtrap_variables;
5665  sigtrap_variables = sh_sigtrap_variables_get();
5666  if (sigtrap_variables == NULL) {
5667    /* Perhaps, it's better to not die, and to continue using Samhain,
5668       even if this part does not work. */
5669    return;
5670  }
5671
5672#ifdef HAVE_GETTIMEOFDAY
5673  {
5674    struct timeval  tv;
5675    long   difftv;
5676   
5677    gettimeofday(&tv, NULL);
5678    difftv = (tv.tv_sec - sigtrap_variables->save_tv.tv_sec) * 1000000 + 
5679      (tv.tv_usec - sigtrap_variables->save_tv.tv_usec);
5680    if (difftv > sh.sigtrap_max_duration)
5681      raise(SIGKILL);
5682  }
5683#endif
5684
5685  sigtrap_variables->not_traced = signum;
5686  /* cppcheck-suppress memleak */
5687  return;
5688}
5689#endif
Note: See TracBrowser for help on using the repository browser.