source: trunk/src/sh_unix.c@ 132

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

Make utility functions thread-safe.

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