source: trunk/src/sh_unix.c@ 131

Last change on this file since 131 was 131, checked in by rainer, 17 years ago

Use thread-safe libc functions.

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