source: trunk/src/sh_unix.c @ 132

Last change on this file since 132 was 132, checked in by rainer, 12 years ago

Make utility functions thread-safe.

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