diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-07-01 10:01:25 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-07-01 10:01:25 +0000 |
commit | c0072ad88a89ffade62dde1ee94c66a0be439ec5 (patch) | |
tree | 56712b726ed37608871c27a5de7b82a8b69b4a27 /src | |
parent | Removing changes outside of debian directory. (diff) | |
download | samhain-c0072ad88a89ffade62dde1ee94c66a0be439ec5.tar.xz samhain-c0072ad88a89ffade62dde1ee94c66a0be439ec5.zip |
Merging upstream version 4.4.10.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src')
67 files changed, 4186 insertions, 8341 deletions
diff --git a/src/#sh_unix.c# b/src/#sh_unix.c# deleted file mode 100644 index 695d46f..0000000 --- a/src/#sh_unix.c# +++ /dev/null @@ -1,5710 +0,0 @@ -/* SAMHAIN file system integrity testing */ -/* Copyright (C) 1999 Rainer Wichmann */ -/* */ -/* This program is free software; you can redistribute it */ -/* and/or modify */ -/* it under the terms of the GNU General Public License as */ -/* published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include "config_xor.h" - - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#ifdef HAVE_LINUX_FS_H -#include <linux/fs.h> -#endif - -#ifdef HAVE_MEMORY_H -#include <memory.h> -#endif - -#ifdef HAVE_UNISTD_H -#include <errno.h> -#include <signal.h> -#include <pwd.h> -#include <grp.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/resource.h> -#include <fcntl.h> -#include <unistd.h> -/* need to undef these, since the #define's may be picked up from - * linux/wait.h, and will clash with a typedef in sys/wait.h - */ -#undef P_ALL -#undef P_PID -#undef P_PGID -#include <sys/wait.h> - -/********************* -#ifdef HAVE_SYS_VFS_H -#include <sys/vfs.h> -#endif -**********************/ -#endif - -#if TIME_WITH_SYS_TIME -#include <sys/time.h> -#include <time.h> -#else -#if HAVE_SYS_TIME_H -#include <sys/time.h> -#else -#include <time.h> -#endif -#endif - -#ifdef HAVE_SYS_SELECT_H -#include <sys/select.h> -#endif - -#ifndef FD_SET -#define NFDBITS 32 -#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) -#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) -#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) -#endif /* !FD_SET */ -#ifndef FD_SETSIZE -#define FD_SETSIZE 32 -#endif -#ifndef FD_ZERO -#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p))) -#endif - - -#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK) -#include <sys/mman.h> -#endif - -#include "samhain.h" -#include "sh_error.h" -#include "sh_unix.h" -#include "sh_utils.h" -#include "sh_mem.h" -#include "sh_hash.h" -#include "sh_tools.h" -#include "sh_restrict.h" -#include "sh_ipvx.h" -#include "sh_tiger.h" -#include "sh_prelink.h" -#include "sh_pthread.h" -#include "sh_sem.h" - -/* moved here from far below - */ -#include <netdb.h> - -#define SH_NEED_PWD_GRP -#define SH_NEED_GETHOSTBYXXX -#include "sh_static.h" - -#ifndef HAVE_LSTAT -#define lstat stat -#endif - -#if defined(S_IFLNK) && !defined(S_ISLNK) -#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) -#else -#if !defined(S_ISLNK) -#define S_ISLNK(mode) (0) -#endif -#endif - -#if defined(S_IFSOCK) && !defined(S_ISSOCK) -#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) -#else -#if !defined(S_ISSOCK) -#define S_ISSOCK(mode) (0) -#endif -#endif - -#if defined(S_IFDOOR) && !defined(S_ISDOOR) -#define S_ISDOOR(mode) (((mode) & S_IFMT) == S_IFDOOR) -#else -#if !defined(S_ISDOOR) -#define S_ISDOOR(mode) (0) -#endif -#endif - -#if defined(S_IFPORT) && !defined(S_ISPORT) -#define S_ISPORT(mode) (((mode) & S_IFMT) == S_IFPORT) -#else -#if !defined(S_ISPORT) -#define S_ISPORT(mode) (0) -#endif -#endif - -#define SH_KEY_NULL _("000000000000000000000000000000000000000000000000") - -#undef FIL__ -#define FIL__ _("sh_unix.c") - -unsigned long mask_PRELINK = MASK_PRELINK_; -unsigned long mask_USER0 = MASK_USER_; -unsigned long mask_USER1 = MASK_USER_; -unsigned long mask_USER2 = MASK_USER_; -unsigned long mask_USER3 = MASK_USER_; -unsigned long mask_USER4 = MASK_USER_; -unsigned long mask_ALLIGNORE = MASK_ALLIGNORE_; -unsigned long mask_ATTRIBUTES = MASK_ATTRIBUTES_; -unsigned long mask_LOGFILES = MASK_LOGFILES_; -unsigned long mask_LOGGROW = MASK_LOGGROW_; -unsigned long mask_READONLY = MASK_READONLY_; -unsigned long mask_NOIGNORE = MASK_NOIGNORE_; - - -extern char **environ; - -int sh_unix_maskreset() -{ - mask_PRELINK = MASK_PRELINK_; - mask_USER0 = MASK_USER_; - mask_USER1 = MASK_USER_; - mask_USER2 = MASK_USER_; - mask_USER3 = MASK_USER_; - mask_USER4 = MASK_USER_; - mask_ALLIGNORE = MASK_ALLIGNORE_; - mask_ATTRIBUTES = MASK_ATTRIBUTES_; - mask_LOGFILES = MASK_LOGFILES_; - mask_LOGGROW = MASK_LOGGROW_; - mask_READONLY = MASK_READONLY_; - mask_NOIGNORE = MASK_NOIGNORE_; - return 0; -} - - -#ifdef SYS_SIGLIST_DECLARED -/* extern const char * const sys_siglist[]; */ -#else -char * sh_unix_siglist (int signum) -{ - switch (signum) - { -#ifdef SIGHUP - case SIGHUP: - return _("Hangup"); -#endif -#ifdef SIGINT - case SIGINT: - return _("Interrupt"); -#endif -#ifdef SIGQUIT - case SIGQUIT: - return _("Quit"); -#endif -#ifdef SIGILL - case SIGILL: - return _("Illegal instruction"); -#endif -#ifdef SIGTRAP - case SIGTRAP: - return _("Trace/breakpoint trap"); -#endif -#ifdef SIGABRT - case SIGABRT: - return _("IOT trap/Abort"); -#endif -#ifdef SIGBUS - case SIGBUS: - return _("Bus error"); -#endif -#ifdef SIGFPE - case SIGFPE: - return _("Floating point exception"); -#endif -#ifdef SIGUSR1 - case SIGUSR1: - return _("User defined signal 1"); -#endif -#ifdef SIGSEGV - case SIGSEGV: - return _("Segmentation fault"); -#endif -#ifdef SIGUSR2 - case SIGUSR2: - return _("User defined signal 2"); -#endif -#ifdef SIGPIPE - case SIGPIPE: - return _("Broken pipe"); -#endif -#ifdef SIGALRM - case SIGALRM: - return _("Alarm clock"); -#endif -#ifdef SIGTERM - case SIGTERM: - return _("Terminated"); -#endif -#ifdef SIGSTKFLT - case SIGSTKFLT: - return _("Stack fault"); -#endif -#ifdef SIGCHLD - case SIGCHLD: - return _("Child exited"); -#endif -#ifdef SIGCONT - case SIGCONT: - return _("Continued"); -#endif -#ifdef SIGSTOP - case SIGSTOP: - return _("Stopped"); -#endif -#ifdef SIGTSTP - case SIGTSTP: - return _("Stop typed at tty"); -#endif -#ifdef SIGTTIN - case SIGTTIN: - return _("Stopped (tty input)"); -#endif -#ifdef SIGTTOU - case SIGTTOU: - return _("Stopped (tty output)"); -#endif -#ifdef SIGURG - case SIGURG: - return _("Urgent condition"); -#endif -#ifdef SIGXCPU - case SIGXCPU: - return _("CPU time limit exceeded"); -#endif -#ifdef SIGXFSZ - case SIGXFSZ: - return _("File size limit exceeded"); -#endif -#ifdef SIGVTALRM - case SIGVTALRM: - return _("Virtual time alarm"); -#endif -#ifdef SIGPROF - case SIGPROF: - return _("Profile signal"); -#endif -#ifdef SIGWINCH - case SIGWINCH: - return _("Window size changed"); -#endif -#ifdef SIGIO - case SIGIO: - return _("Possible I/O"); -#endif -#ifdef SIGPWR - case SIGPWR: - return _("Power failure"); -#endif -#ifdef SIGUNUSED - case SIGUNUSED: - return _("Unused signal"); -#endif - } - return _("Unknown"); -} -#endif - - -/* Log from within a signal handler without using any - * functions that are not async signal safe. - * - * This is the safe_itoa helper function. - */ -char * safe_itoa(int i, char * str, int size) -{ - unsigned int u; - int iisneg = 0; - char *p = &str[size-1]; - - *p = '\0'; - if (i < 0) { - iisneg = 1; - u = ((unsigned int)(-(1+i))) + 1; - } else { - u = i; - } - do { - --p; - *p = '0' + (u % 10); - u /= 10; - } while (u && (p != str)); - if ((iisneg == 1) && (p != str)) { - --p; - *p = '-'; - } - return p; -} - -/* Log from within a signal handler without using any - * functions that are not async signal safe. - * - * This is the safe_logger function. - * Arguments: signal (signal number), method (0=logger, 1=stderr), thepid (pid) - */ -extern int OnlyStderr; - -int safe_logger (int thesignal, int method, char * details) -{ - unsigned int i = 0; - int status = -1; - struct stat buf; - pid_t newpid; - char str[128]; - char * p; - - char l0[64], l1[64], l2[64], l3[64]; - char a0[32]; - char e0[128]; - char msg[128]; - - char * locations[] = { NULL, NULL, NULL, NULL, NULL }; - char * envp[] = { NULL, NULL }; - char * argp[] = { NULL, NULL, NULL }; - - pid_t thepid = getpid(); - - if ((sh.flag.isdaemon == S_FALSE) || (OnlyStderr == S_TRUE)) - method = 1; - - /* seems that solaris cc needs this way of initializing ... - */ - locations[0] = l0; - locations[1] = l1; - locations[2] = l2; - locations[3] = l3; - - envp[0] = e0; - argp[0] = a0; - - sl_strlcpy(msg, _("samhain["), 128); - p = safe_itoa((int) thepid, str, 128); - if (p && *p) - sl_strlcat(msg, p, 128); - if (thesignal == 0) - { - if (details == NULL) { - sl_strlcat(msg, _("]: out of memory"), 128); - } else { - sl_strlcat(msg, _("]: "), 128); - sl_strlcat(msg, details, 128); - } - } - else - { - sl_strlcat(msg, _("]: exit on signal "), 128); - p = safe_itoa(thesignal, str, 128); - if (p && *p) - sl_strlcat(msg, p, 128); - } - - if (method == 1) { -#ifndef STDERR_FILENO -#define STDERR_FILENO 2 -#endif - int retval = 0; - do { - retval = write(STDERR_FILENO, msg, strlen(msg)); - } while (retval < 0 && errno == EINTR); - do { - retval = write(STDERR_FILENO, "\n", 1); - } while (retval < 0 && errno == EINTR); - return 0; - } - - sl_strlcpy (l0, _("/usr/bin/logger"), 64); - sl_strlcpy (l1, _("/usr/sbin/logger"), 64); - sl_strlcpy (l2, _("/usr/ucb/logger"), 64); - sl_strlcpy (l3, _("/bin/logger"), 64); - - sl_strlcpy (a0, _("logger"), 32); - sl_strlcpy (e0, - _("PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/ucb:/usr/local/bin"), - 128); - - while (locations[i] != NULL) { - status = stat(locations[i], &buf); - if (status == 0) - break; - ++i; - } - - if (locations[i] != NULL) { - argp[1] = msg; - newpid = fork(); - if (newpid == 0) { - execve(locations[i], argp, envp); - _exit(1); - } - else if (newpid > 0) { - waitpid(newpid, &status, WUNTRACED); - } - } - return 0; -} - -void safe_fatal (const char * details, - const char * file, int line) -{ - char msg[128]; - char str[128]; - char * p; - int thesignal = 0; - int method = 0; - - p = safe_itoa((int) line, str, 128); - sl_strlcpy(msg, _("FATAL: "), 128); - sl_strlcat(msg, file, 128); - sl_strlcat(msg, ": ", 128); - if (p && (*p)) { - sl_strlcat(msg, p , 128); - sl_strlcat(msg, ": ", 128); - } - sl_strlcat(msg, details, 128); - (void) safe_logger (thesignal, method, msg); - - close_ipc (); - raise(SIGKILL); -} - -extern char sh_sig_msg[64]; - -volatile int immediate_exit_normal = 0; - -#if defined(SA_SIGACTION_WORKS) -static -void sh_unix_sigexit (int mysignal, siginfo_t * signal_info, void * signal_add) -#else -static -void sh_unix_sigexit (int mysignal) -#endif -{ - -#if defined(SA_SIGACTION_WORKS) - if (signal_info != NULL && signal_info->si_code == SI_USER && - mysignal != SIGTERM && mysignal != SIGINT) - { - return; - } - - /* avoid compiler warning (unused var) - */ - (void) signal_add; -#endif - - /* - * Block re-entry - */ - if (immediate_exit_normal > 0) - { - ++immediate_exit_normal; - if ((skey != NULL) && (immediate_exit_normal == 2)) - memset (skey, '\0', sizeof(sh_key_t)); - if (immediate_exit_normal == 2) - { - int val_return; - - do { - val_return = chdir ("/"); - } while (val_return < 0 && errno == EINTR); - - close_ipc (); - safe_logger (mysignal, 0, NULL); - } - raise(SIGKILL); - } - else - { - immediate_exit_normal = 1; - } - -#ifdef SYS_SIGLIST_DECLARED - strncpy (sh_sig_msg, sys_siglist[mysignal], 40); -#else - strncpy (sh_sig_msg, sh_unix_siglist(mysignal), 40); -#endif - sh_sig_msg[63] = '\0'; - - ++sig_raised; - ++sig_urgent; - sig_termfast = 1; - return; -} - -volatile int immediate_exit_fast = 0; - -#if defined(SA_SIGACTION_WORKS) -static -void sh_unix_sigexit_fast (int mysignal, siginfo_t * signal_info, - void * signal_add) -#else -static -void sh_unix_sigexit_fast (int mysignal) -#endif -{ -#if defined(SL_DEBUG) && (defined(USE_SYSTEM_MALLOC) || !defined(USE_MALLOC_LOCK)) - int retval; -#endif - -#if defined(SA_SIGACTION_WORKS) - if (signal_info != NULL && signal_info->si_code == SI_USER) - { - return; - } -#endif - - /* avoid compiler warning (unused var) - */ -#if defined(SA_SIGACTION_WORKS) - (void) signal_add; -#endif - - /* Check whether the heap is ok; otherwise _exit - */ -#if !defined(SL_DEBUG) || (!defined(USE_SYSTEM_MALLOC) && defined(USE_MALLOC_LOCK)) - ++immediate_exit_fast; - if (skey != NULL && immediate_exit_fast < 2) - memset (skey, '\0', sizeof(sh_key_t)); - if (immediate_exit_fast < 2) - safe_logger (mysignal, 0, NULL); - raise(SIGKILL); -#else - - /* debug code - */ - if (immediate_exit_fast == 1) - { - ++immediate_exit_fast; - if (skey != NULL) - memset (skey, '\0', sizeof(sh_key_t)); - close_ipc (); - safe_logger (mysignal, 0, NULL); - do { - retval = chdir ("/"); - } while (retval < 0 && errno == EINTR); - raise(SIGFPE); - } - else if (immediate_exit_fast == 2) - { - do { - retval = chdir ("/"); - } while (retval < 0 && errno == EINTR); - raise(SIGFPE); - } - else if (immediate_exit_fast != 0) - { - raise(SIGKILL); - } - - ++immediate_exit_fast; - - /* The FPE|BUS|SEGV|ILL signals leave the system in an undefined - * state, thus it is best to exit immediately. - */ -#ifdef SYS_SIGLIST_DECLARED - strncpy (sh_sig_msg, sys_siglist[mysignal], 40); -#else - strncpy (sh_sig_msg, sh_unix_siglist(mysignal), 40); -#endif - sh_sig_msg[63] = '\0'; - - sl_stack_print(); - - /* Try to push out an error message. - */ - sh_error_handle ((-1), FIL__, __LINE__, mysignal, MSG_EXIT_NORMAL, - sh.prg_name, sh_sig_msg); - - if (skey != NULL) - memset (skey, '\0', sizeof(sh_key_t)); - close_ipc (); - - do { - retval = chdir ("/"); - } while (retval < 0 && errno == EINTR); - - raise(SIGFPE); -#endif -} - - -static -void sh_unix_sigaction (int mysignal) -{ - ++sig_raised; -#ifdef SIGUSR1 - if (mysignal == SIGUSR1) - sig_debug_switch = 1; -#endif -#ifdef SIGUSR2 - if (mysignal == SIGUSR2) - { - ++sig_suspend_switch; - ++sig_urgent; - } -#endif -#ifdef SIGHUP - if (mysignal == SIGHUP) - sig_config_read_again = 1; -#endif -#ifdef SIGTTOU - if (mysignal == SIGTTOU) { - sig_force_check = 1; sh_sem_trylock(); } -#endif -#ifdef SIGTSTP - if (mysignal == SIGTSTP) { - sig_force_check = 1; sig_force_silent = 1; sh_sem_trylock(); } -#endif -#ifdef SIGTTIN - if (mysignal == SIGTTIN) - sig_fresh_trail = 1; -#endif -#ifdef SIGABRT - if (mysignal == SIGABRT) - sig_fresh_trail = 1; -#endif -#ifdef SIGQUIT - if (mysignal == SIGQUIT) - sig_terminate = 1; -#endif -#ifdef SIGTERM - if (mysignal == SIGTERM) - { - strncpy (sh_sig_msg, _("Terminated"), 40); - sig_termfast = 1; - ++sig_urgent; - } -#endif - - return; -} - -void sh_unix_ign_sigpipe() -{ - struct sigaction ignact; - - ignact.sa_handler = SIG_IGN; /* signal action */ - sigemptyset( &ignact.sa_mask ); /* set an empty mask */ - ignact.sa_flags = 0; /* init sa_flags */ - -#ifdef SIGPIPE - retry_sigaction(FIL__, __LINE__, SIGPIPE, &ignact, NULL); -#endif - - return; -} -static -void sh_unix_siginstall (int goDaemon) -{ - struct sigaction act, act_fast, act2, oldact, ignact; -#if defined (SH_WITH_SERVER) - (void) goDaemon; -#endif - - SL_ENTER(_("sh_unix_siginstall")); - - ignact.sa_handler = SIG_IGN; /* signal action */ - sigemptyset( &ignact.sa_mask ); /* set an empty mask */ - ignact.sa_flags = 0; /* init sa_flags */ - -#if defined(SA_SIGACTION_WORKS) - act.sa_sigaction = &sh_unix_sigexit; /* signal action */ -#else - act.sa_handler = &sh_unix_sigexit; /* signal action */ -#endif - - sigfillset ( &act.sa_mask ); /* set a full mask */ - - - /* Block all but deadly signals. - */ -#ifdef SIGILL - sigdelset ( &act.sa_mask, SIGILL ); -#endif -#ifndef SL_DEBUG -#ifdef SIGFPE - sigdelset ( &act.sa_mask, SIGFPE ); -#endif -#endif -#ifdef SIGSEGV - sigdelset ( &act.sa_mask, SIGSEGV ); -#endif -#ifdef SIGBUS - sigdelset ( &act.sa_mask, SIGBUS ); -#endif - -#if defined(SA_SIGACTION_WORKS) - act_fast.sa_sigaction = &sh_unix_sigexit_fast; /* signal action */ -#else - act_fast.sa_handler = &sh_unix_sigexit_fast; /* signal action */ -#endif - - sigfillset ( &act_fast.sa_mask ); /* set a full mask */ - -#ifdef SIGILL - sigdelset ( &act_fast.sa_mask, SIGILL ); -#endif -#ifndef SL_DEBUG -#ifdef SIGFPE - sigdelset ( &act_fast.sa_mask, SIGFPE ); -#endif -#endif -#ifdef SIGSEGV - sigdelset ( &act_fast.sa_mask, SIGSEGV ); -#endif -#ifdef SIGBUS - sigdelset ( &act_fast.sa_mask, SIGBUS ); -#endif - - - /* Use siginfo to verify origin of signal, if possible. - */ -#if defined(SA_SIGACTION_WORKS) - act.sa_flags = SA_SIGINFO; - act_fast.sa_flags = SA_SIGINFO; -#else - act.sa_flags = 0; - act_fast.sa_flags = 0; -#endif - - /* Do not block the signal from being received in its handler ... - * (is this a good or a bad idea ??). - */ -#if defined(SA_NOMASK) - act_fast.sa_flags |= SA_NOMASK; -#elif defined(SA_NODEFER) - act_fast.sa_flags |= SA_NODEFER; -#endif - - - act2.sa_handler = &sh_unix_sigaction; /* signal action */ - sigemptyset( &act2.sa_mask ); /* set an empty mask */ - act2.sa_flags = 0; /* init sa_flags */ - - /* signals to control the daemon */ - -#ifdef SIGHUP - retry_sigaction(FIL__, __LINE__, SIGHUP, &act2, &oldact); -#endif -#ifdef SIGABRT - retry_sigaction(FIL__, __LINE__, SIGABRT, &act2, &oldact); -#endif -#ifdef SIGUSR1 - retry_sigaction(FIL__, __LINE__, SIGUSR1, &act2, &oldact); -#endif -#ifdef SIGUSR2 - retry_sigaction(FIL__, __LINE__, SIGUSR2, &act2, &oldact); -#endif -#ifdef SIGQUIT - retry_sigaction(FIL__, __LINE__, SIGQUIT, &act2, &oldact); -#endif -#ifdef SIGTERM - retry_sigaction(FIL__, __LINE__, SIGTERM, &act, &oldact); -#endif - - /* fatal signals that may cause termination */ - -#ifdef SIGILL - retry_sigaction(FIL__, __LINE__, SIGILL, &act_fast, &oldact); -#endif -#ifndef SL_DEBUG -#ifdef SIGFPE - retry_sigaction(FIL__, __LINE__, SIGFPE, &act_fast, &oldact); -#endif -#endif -#ifdef SIGSEGV - retry_sigaction(FIL__, __LINE__, SIGSEGV, &act_fast, &oldact); -#endif -#ifdef SIGBUS - retry_sigaction(FIL__, __LINE__, SIGBUS, &act_fast, &oldact); -#endif - - /* other signals */ - -#ifdef SIGINT - retry_sigaction(FIL__, __LINE__, SIGINT, &act, &oldact); -#endif -#ifdef SIGPIPE - retry_sigaction(FIL__, __LINE__, SIGPIPE, &ignact, &oldact); -#endif -#ifdef SIGALRM - retry_sigaction(FIL__, __LINE__, SIGALRM, &ignact, &oldact); -#endif - -#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) -#ifdef SIGTTOU - if (goDaemon == 1) - retry_sigaction(FIL__, __LINE__, SIGTTOU, &act2, &oldact); - else - retry_sigaction(FIL__, __LINE__, SIGTTOU, &ignact, &oldact); -#endif -#ifdef SIGTSTP - if (goDaemon == 1) - retry_sigaction(FIL__, __LINE__, SIGTSTP, &act2, &oldact); - else - retry_sigaction(FIL__, __LINE__, SIGTSTP, &ignact, &oldact); -#endif -#ifdef SIGTTIN - if (goDaemon == 1) - retry_sigaction(FIL__, __LINE__, SIGTTIN, &act2, &oldact); - else - retry_sigaction(FIL__, __LINE__, SIGTTIN, &ignact, &oldact); -#endif -#else -#ifdef SIGTSTP - retry_sigaction(FIL__, __LINE__, SIGTSTP, &ignact, &oldact); -#endif -#ifdef SIGTTOU - retry_sigaction(FIL__, __LINE__, SIGTTOU, &ignact, &oldact); -#endif -#ifdef SIGTTIN - retry_sigaction(FIL__, __LINE__, SIGTTIN, &ignact, &oldact); -#endif -#endif - -#ifdef SIGTRAP -#if !defined(SCREW_IT_UP) - retry_sigaction(FIL__, __LINE__, SIGTRAP, &act, &oldact); -#endif -#endif - -#ifdef SIGPOLL - retry_sigaction(FIL__, __LINE__, SIGPOLL, &ignact, &oldact); -#endif -#if defined(SIGPROF) && !defined(SH_PROFILE) - retry_sigaction(FIL__, __LINE__, SIGPROF, &ignact, &oldact); -#endif -#ifdef SIGSYS - retry_sigaction(FIL__, __LINE__, SIGSYS, &act, &oldact); -#endif -#ifdef SIGURG - retry_sigaction(FIL__, __LINE__, SIGURG, &ignact, &oldact); -#endif -#if defined(SIGVTALRM) && !defined(SH_PROFILE) - retry_sigaction(FIL__, __LINE__, SIGVTALRM, &ignact, &oldact); -#endif -#ifdef SIGXCPU - retry_sigaction(FIL__, __LINE__, SIGXCPU, &act, &oldact); -#endif -#ifdef SIGXFSZ - retry_sigaction(FIL__, __LINE__, SIGXFSZ, &act, &oldact); -#endif - -#ifdef SIGEMT - retry_sigaction(FIL__, __LINE__, SIGEMT, &ignact, &oldact); -#endif -#ifdef SIGSTKFLT - retry_sigaction(FIL__, __LINE__, SIGSTKFLT, &act, &oldact); -#endif -#ifdef SIGIO - retry_sigaction(FIL__, __LINE__, SIGIO, &ignact, &oldact); -#endif -#ifdef SIGPWR - retry_sigaction(FIL__, __LINE__, SIGPWR, &act, &oldact); -#endif - -#ifdef SIGLOST - retry_sigaction(FIL__, __LINE__, SIGLOST, &ignact, &oldact); -#endif -#ifdef SIGUNUSED - retry_sigaction(FIL__, __LINE__, SIGUNUSED, &ignact, &oldact); -#endif - - SL_RET0(_("sh_unix_siginstall")); -} - -/* ---------------------------------------------------------------- */ - -/* checksum the own binary - */ -int sh_unix_self_hash (const char * c) -{ - char message[512]; - char hashbuf[KEYBUF_SIZE]; - - SL_ENTER(_("sh_unix_self_hash")); - - if (c == NULL) - { - sh.exec.path[0] = '\0'; - SL_RETURN((0), _("sh_unix_self_hash")); - } - sl_strlcpy(sh.exec.path, c, SH_PATHBUF); - - sl_strlcpy(sh.exec.hash, - sh_tiger_hash (c, TIGER_FILE, TIGER_NOLIM, hashbuf, sizeof(hashbuf)), - KEY_LEN+1); - sl_snprintf(message, 512, _("%s has checksum: %s"), - sh.exec.path, sh.exec.hash); - message[511] = '\0'; - sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN, - message, _("sh_unix_self_hash")); - if (0 == sl_strcmp(sh.exec.hash, SH_KEY_NULL )) - { - dlog(1, FIL__, __LINE__, - _("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"), - sh.exec.path, sl_get_errmsg(), (int) sl_ret_euid()); - sh_error_handle ((-1), FIL__, __LINE__, EACCES, MSG_NOACCESS, - (long) sh.real.uid, c); - aud_exit (FIL__, __LINE__, EXIT_FAILURE); - } - SL_RETURN((0), _("sh_unix_self_hash")); -} - -int sh_unix_self_check () -{ - char newhash[KEY_LEN+1]; - char message[512]; - char hashbuf[KEYBUF_SIZE]; - - SL_ENTER(_("sh_unix_self_check")); - if (sh.exec.path[0] == '\0') - SL_RETURN((0), _("sh_unix_self_check")); - - sl_strlcpy(newhash, - sh_tiger_hash (sh.exec.path, TIGER_FILE, TIGER_NOLIM, hashbuf, sizeof(hashbuf)), - KEY_LEN+1); - - if (0 == sl_strncmp(sh.exec.hash, newhash, KEY_LEN)) - { - sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN, - _("Checksum ok"), _("sh_unix_self_check")); - SL_RETURN((0), _("sh_unix_self_check")); - } - - if (0 == sl_strncmp(SH_KEY_NULL, newhash, KEY_LEN)) - { - sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN, - _("Could not read samhain executable"), _("sh_unix_self_check")); - SL_RETURN((0), _("sh_unix_self_check")); - } - - dlog(1, FIL__, __LINE__, - _("The checksum of the executable: %s has changed since startup (%s -> %s).\n"), - sh.exec.path, sh.exec.hash, newhash); - - sl_snprintf(message, 512, - _("The checksum of %s has changed since startup (%s -> %s)"), - sh.exec.path, sh.exec.hash, newhash); - message[511] = '\0'; - - sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN, - message, _("sh_unix_self_check")); - sh_error_handle ((-1), FIL__, __LINE__, EACCES, MSG_E_AUTH, - sh.exec.path); - SL_RETURN((-1), _("sh_unix_self_check")); -} - - -/* ---------------------------------------------------------------- */ - -long sh_group_to_gid (const char * g, int * fail) -{ - struct group * w; - gid_t gid = 0; - int status = 0; - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R) - struct group grp; - char * buffer; - static size_t gbufsize = SH_GRBUF_SIZE; -#endif - - *fail = -1; - - if (g) - { - size_t i; - size_t len = strlen(g); - - *fail = 0; - - for (i = 0; i < len; ++i) - { - char c = g[i]; - - if (!isdigit((int) c)) - goto is_a_name; - } - return atol(g); - - is_a_name: - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R) - - buffer = SH_ALLOC(gbufsize); - status = sh_getgrnam_r(g, &grp, buffer, gbufsize, &w); - - if ((status == ERANGE) && (w == NULL)) - { - if (S_TRUE == sl_ok_adds( gbufsize, SH_GRBUF_SIZE )) - { - SH_FREE(buffer); - gbufsize += SH_GRBUF_SIZE; - goto is_a_name; - } - } - -#else - - errno = 0; - w = sh_getgrnam(g); - status = errno; - -#endif - - if ((status == ERANGE) && (w == NULL)) - { - static int seen = 0; - - if (seen == 0) - { - char errbuf[SH_ERRBUF_SIZE]; - - sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_GRNULL, - sh_error_message(status, errbuf, sizeof(errbuf)), - _("sh_group_to_gid"), (long) -1, _("line too long in group entry")); - ++seen; - } - *fail = -1; - } - else if (w == NULL) - { - char * tmp = sh_util_strdup(g); - sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS, - _("sh_group_to_gid"), tmp); - SH_FREE(tmp); - *fail = -1; - } - else - { - gid = w->gr_gid; - } -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R) - SH_FREE(buffer); -#endif - } - - return gid; -} - -/* ---------------------------------------------------------------- */ - - -/* added Tue Feb 22 10:36:44 NFT 2000 Rainer Wichmann */ -static int tf_add_trusted_user_int(const char * c) -{ - struct passwd * w; - int count; - uid_t pwid = (uid_t)-1; - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R) - struct passwd pwd; - char * buffer; -#endif - - SL_ENTER(_("tf_add_trusted_user_int")); - - /* First check for a user name. - */ -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R) - buffer = SH_ALLOC(SH_PWBUF_SIZE); - sh_getpwnam_r(c, &pwd, buffer, SH_PWBUF_SIZE, &w); -#else - w = sh_getpwnam(c); -#endif - - if ((w != NULL) && ((pwid = w->pw_uid) > 0)) - goto succe; - - /* Failed, so check for a numerical value. - */ - pwid = strtol(c, (char **)NULL, 10); - if (pwid > 0 && pwid < 65535) - goto succe; - - sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS, - _("add trusted user"), c); -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R) - SH_FREE(buffer); -#endif - SL_RETURN((-1), _("tf_add_trusted_user_int")); - - succe: - count = sl_trust_add_user(pwid); -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R) - SH_FREE(buffer); -#endif - SL_RETURN((count), _("tf_add_trusted_user_int")); -} - -int tf_add_trusted_user(const char * c) -{ - int i; - char * q; - char * p = sh_util_strdup (c); -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R) - char * saveptr; -#endif - - SL_ENTER(_("tf_add_trusted_user")); - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R) - q = strtok_r(p, ", \t", &saveptr); -#else - q = strtok(p, ", \t"); -#endif - if (!q) - { - SH_FREE(p); - SL_RETURN((-1), _("tf_add_trusted_user")); - } - while (q) - { - i = tf_add_trusted_user_int(q); - if (SL_ISERROR(i)) - { - SH_FREE(p); - SL_RETURN((i), _("tf_add_trusted_user")); - } -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R) - q = strtok_r(NULL, ", \t", &saveptr); -#else - q = strtok(NULL, ", \t"); -#endif - } - SH_FREE(p); - SL_RETURN((0), _("tf_add_trusted_user")); -} - -extern uid_t sl_trust_baduid(void); -extern gid_t sl_trust_badgid(void); - -#if defined(HOST_IS_CYGWIN) || defined(__cygwin__) || defined(__CYGWIN32__) || defined(__CYGWIN__) -int tf_trust_check (const char * file, int mode) -{ - (void) file; - (void) mode; - return 0; -} -#else -int tf_trust_check (const char * file, int mode) -{ - char * tmp; - char * tmp2; - char * p; - int status; - int level; - uid_t ff_euid = (uid_t) -1; - - SL_ENTER(_("tf_trust_check")); - - if (mode == SL_YESPRIV) - sl_get_euid(&ff_euid); - else - sl_get_ruid(&ff_euid); - -#if defined(SH_WITH_SERVER) - if (0 == sl_ret_euid()) /* privileges not dropped yet */ - { -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R) - struct passwd pwd; - char * buffer = SH_ALLOC(SH_PWBUF_SIZE); - struct passwd * tempres; - sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres); -#else - struct passwd * tempres = sh_getpwnam(DEFAULT_IDENT); -#endif - - if (!tempres) - { - dlog(1, FIL__, __LINE__, - _("User %s does not exist. Please add the user to your system.\n"), - DEFAULT_IDENT); - aud_exit (FIL__, __LINE__, EXIT_FAILURE); - } - else - { - ff_euid = tempres->pw_uid; - } -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R) - SH_FREE(buffer); -#endif - } -#endif - - status = sl_trustfile_euid(file, ff_euid); - - if ( SL_ENONE != status) - { - if (status == SL_ESTAT) - level = SH_ERR_ALL; - else - level = SH_ERR_ERR; - - tmp = sh_util_safe_name (file); - p = sl_trust_errfile(); - if (p && *p != '\0') - { - tmp2 = sh_util_safe_name (sl_trust_errfile()); - sh_error_handle(level, FIL__, __LINE__, status, MSG_E_TRUST2, - sl_error_string(status), tmp, tmp2); - SH_FREE(tmp2); - } - else - { - sh_error_handle(level, FIL__, __LINE__, status, MSG_E_TRUST1, - sl_error_string(status), tmp); - } - SH_FREE(tmp); - - if (status == SL_EBADUID || status == SL_EBADGID || - status == SL_EBADOTH || status == SL_ETRUNC || - status == SL_EINTERNAL ) - { - switch (status) { - case SL_EINTERNAL: - dlog(1, FIL__, __LINE__, - _("An internal error occured in the trustfile function.\n")); - break; - case SL_ETRUNC: - tmp = sh_util_safe_name (file); - dlog(1, FIL__, __LINE__, - _("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"), - tmp); - SH_FREE(tmp); - break; - case SL_EBADOTH: - tmp = sh_util_safe_name (file); - p = sl_trust_errfile(); - dlog(1, FIL__, __LINE__, - _("The path element: %s\nin the filename: %s is world writeable.\n"), - p, tmp); - SH_FREE(tmp); - break; - case SL_EBADUID: - tmp = sh_util_safe_name (file); - p = sl_trust_errfile(); - dlog(1, FIL__, __LINE__, - _("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"), - (UID_CAST)sl_trust_baduid(), p, tmp); - SH_FREE(tmp); - break; - case SL_EBADGID: - tmp = sh_util_safe_name (file); - p = sl_trust_errfile(); - dlog(1, FIL__, __LINE__, - _("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"), - p, tmp, (UID_CAST)sl_trust_badgid(), - (UID_CAST)sl_trust_baduid()); - SH_FREE(tmp); - break; - default: - break; - } - - SL_RETURN((-1), _("tf_trust_check")); - } - } - - SL_RETURN((0), _("tf_trust_check")); -} -#endif - -#ifdef HAVE_INITGROUPS -#ifdef HOST_IS_OSF -int sh_unix_initgroups ( char * in_user, gid_t in_gid) -#else -int sh_unix_initgroups (const char * in_user, gid_t in_gid) -#endif -{ - int status = -1; - status = sh_initgroups (in_user, in_gid); - if (status < 0) - { - if (errno == EPERM) - return 0; - if (errno == EINVAL) - return 0; - return -1; - } - return 0; -} -#else -int sh_unix_initgroups (const char * in_user, gid_t in_gid) -{ - (void) in_user; - (void) in_gid; - return 0; -} -#endif - -#ifdef HAVE_INITGROUPS -char * sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len); -int sh_unix_initgroups2 (uid_t in_pid, gid_t in_gid) -{ - int status = -1; - char user[SH_MINIBUF]; - - SL_ENTER(_("sh_unix_initgroups2")); - - if (NULL == sh_unix_getUIDname (SH_ERR_ERR, in_pid, user, sizeof(user))) - SL_RETURN((-1), _("sh_unix_initgroups2")); - status = sh_initgroups (user, in_gid); - if (status < 0) - { - if (errno == EPERM) - status = 0; - if (errno == EINVAL) - status = 0; - } - SL_RETURN((status), _("sh_unix_initgroups2")); -} -#else -int sh_unix_initgroups2 (uid_t in_pid, gid_t in_gid) -{ - (void) in_pid; - (void) in_gid; - return 0; -} -#endif - -void sh_unix_closeall (int fd, int except, int inchild) -{ - int fdx = fd; -#ifdef _SC_OPEN_MAX - int fdlimit = sysconf (_SC_OPEN_MAX); -#else -#ifdef OPEN_MAX - int fdlimit = OPEN_MAX; -#else - int fdlimit = _POSIX_OPEN_MAX; -#endif -#endif - - SL_ENTER(_("sh_unix_closeall")); - - /* can't happen - so fix it :-( - */ - if (fdlimit < 0) - fdlimit = 20; /* POSIX lower limit */ - - if (fdlimit > 65536) - fdlimit = 65536; - - if (!inchild) - sl_dropall (fdx, except); - else - sl_dropall_dirty (fdx, except); - - /* Close everything from fd (inclusive) up to fdlimit (exclusive). - */ - while (fd < fdlimit) - { - if (fd == except) - fd++; - else if (slib_do_trace != 0 && fd == slib_trace_fd) - fd++; - else - sl_close_fd(FIL__, __LINE__, fd++); - } - - SL_RET0(_("sh_unix_closeall")); -} - -static void sh_unix_setlimits(void) -{ - struct rlimit limits; - - SL_ENTER(_("sh_unix_setlimits")); - - limits.rlim_cur = RLIM_INFINITY; - limits.rlim_max = RLIM_INFINITY; - -#ifdef RLIMIT_CPU - setrlimit (RLIMIT_CPU, &limits); -#endif -#ifdef RLIMIT_FSIZE - setrlimit (RLIMIT_FSIZE, &limits); -#endif -#ifdef RLIMIT_DATA - setrlimit (RLIMIT_DATA, &limits); -#endif -#ifdef RLIMIT_STACK - setrlimit (RLIMIT_STACK, &limits); -#endif -#ifdef RLIMIT_RSS - setrlimit (RLIMIT_RSS, &limits); -#endif -#ifdef RLIMIT_NPROC - setrlimit (RLIMIT_NPROC, &limits); -#endif -#ifdef RLIMIT_MEMLOCK - setrlimit (RLIMIT_MEMLOCK, &limits); -#endif - -#if !defined(SL_DEBUG) - /* no core dumps - */ - limits.rlim_cur = 0; - limits.rlim_max = 0; -#ifdef RLIMIT_CORE - setrlimit (RLIMIT_CORE, &limits); -#endif -#else -#ifdef RLIMIT_CORE - setrlimit (RLIMIT_CORE, &limits); -#endif -#endif - - limits.rlim_cur = 1024; - limits.rlim_max = 1024; - -#if defined(RLIMIT_NOFILE) - setrlimit (RLIMIT_NOFILE, &limits); -#elif defined(RLIMIT_OFILE) - setrlimit (RLIMIT_OFILE, &limits); -#endif - - SL_RET0(_("sh_unix_setlimits")); -} - -static void sh_unix_copyenv(void) -{ - char ** env0 = environ; - char ** env1; - int envlen = 0; - size_t len; - - SL_ENTER(_("sh_unix_copyenv")); - - while (env0 != NULL && env0[envlen] != NULL) { - /* printf("%2d: %s\n", envlen, env0[envlen]); */ - ++envlen; - } - ++envlen; - - /* printf("-> %2d: slots allocated\n", envlen); */ - env1 = calloc(1,sizeof(char *) * envlen); /* only once */ - if (env1 == NULL) - { - fprintf(stderr, _("%s: %d: Out of memory\n"), FIL__, __LINE__); - SL_RET0(_("sh_unix_copyenv")); - } - env0 = environ; - envlen = 0; - - while (env0 != NULL && env0[envlen] != NULL) { - len = strlen(env0[envlen]) + 1; - env1[envlen] = calloc(1,len); /* only once */ - if (env1[envlen] == NULL) - { - int i; - fprintf(stderr, _("%s: %d: Out of memory\n"), FIL__, __LINE__); - for (i = 0; i < envlen; ++i) free(env1[len]); - free(env1); - SL_RET0(_("sh_unix_copyenv")); - } - sl_strlcpy(env1[envlen], env0[envlen], len); - ++envlen; - } - env1[envlen] = NULL; - - environ = env1; - SL_RET0(_("sh_unix_copyenv")); -} - -/* delete all environment variables - */ -static void sh_unix_zeroenv(void) -{ - char * c; - char ** env; - - SL_ENTER(_("sh_unix_zeroenv")); - - sh_unix_copyenv(); - env = environ; - - while (env != NULL && *env != NULL) { - c = strchr ((*env), '='); -#ifdef WITH_MYSQL - /* - * Skip the MYSQL_UNIX_PORT environment variable; MySQL may need it. - */ - if (0 == sl_strncmp((*env), _("MYSQL_UNIX_PORT="), 16)) - { - ++(env); - continue; - } - if (0 == sl_strncmp((*env), _("MYSQL_TCP_PORT="), 15)) - { - ++(env); - continue; - } - if (0 == sl_strncmp((*env), _("MYSQL_HOME="), 11)) - { - ++(env); - continue; - } -#endif -#ifdef WITH_ORACLE - /* - * Skip the ORACLE_HOME and TNS_ADMIN environment variables; - * Oracle may need them. - */ - if (0 == sl_strncmp((*env), _("ORACLE_HOME="), 12)) - { - ++(env); - continue; - } - if (0 == sl_strncmp((*env), _("TNS_ADMIN="), 10)) - { - ++(env); - continue; - } -#endif - /* - * Skip the TZ environment variable. - */ - if (0 == sl_strncmp((*env), _("TZ="), 3)) - { - ++(env); - continue; - } - ++(env); - if (c != NULL) - { - ++c; - while ((*c) != '\0') { - (*c) = '\0'; - ++c; - } - } - } - -#ifdef HAVE_TZSET - tzset(); -#endif - - SL_RET0(_("sh_unix_zeroenv")); -} - - -static void sh_unix_resettimer(void) -{ - struct itimerval this_timer; - - SL_ENTER(_("sh_unix_resettimer")); - - this_timer.it_value.tv_sec = 0; - this_timer.it_value.tv_usec = 0; - - this_timer.it_interval.tv_sec = 0; - this_timer.it_interval.tv_usec = 0; - - setitimer(ITIMER_REAL, &this_timer, NULL); -#if !defined(SH_PROFILE) - setitimer(ITIMER_VIRTUAL, &this_timer, NULL); - setitimer(ITIMER_PROF, &this_timer, NULL); -#endif - - SL_RET0(_("sh_unix_resettimer")); -} - -static void sh_unix_resetsignals(void) -{ - int sig_num; -#ifdef NSIG - int max_sig = NSIG; -#else - int max_sig = 255; -#endif - int test; - int status; - struct sigaction act; -#if !defined(SH_PROFILE) - struct sigaction oldact; -#endif - - sigset_t set_proc; - - SL_ENTER(_("sh_unix_resetsignals")); - /* - * Reset the current signal mask (inherited from parent process). - */ - - sigfillset(&set_proc); - - do { - errno = 0; - test = SH_SETSIGMASK(SIG_UNBLOCK, &set_proc, NULL); - } while (test < 0 && errno == EINTR); - - /* - * Reset signal handling. - */ - - act.sa_handler = SIG_DFL; /* signal action */ - sigemptyset( &act.sa_mask ); /* set an empty mask */ - act.sa_flags = 0; /* init sa_flags */ - - for (sig_num = 1; sig_num <= max_sig; ++sig_num) - { -#if !defined(SH_PROFILE) - test = retry_sigaction(FIL__, __LINE__, sig_num, &act, &oldact); -#else - test = 0; -#endif - if ((test == -1) && (errno != EINVAL)) - { - char errbuf[SH_ERRBUF_SIZE]; - status = errno; - sh_error_handle ((-1), FIL__, __LINE__, status, MSG_W_SIG, - sh_error_message (status, errbuf, sizeof(errbuf)), sig_num); - } - } - - SL_RET0(_("sh_unix_resetsignals")); -} - -/* Get the local hostname (FQDN) - */ -static char * sh_tolower (char * s) -{ - char * ret = s; - if (s) - { - for (; *s; ++s) - { - *s = tolower((unsigned char) *s); - } - } - return ret; -} - - -#include <sys/socket.h> - -/* Required for BSD - */ -#ifdef HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif - -#include <arpa/inet.h> - -const char * sh_unix_h_name (struct hostent * host_entry) -{ - char ** p; - if (strchr(host_entry->h_name, '.')) { - return host_entry->h_name; - } else { - for (p = host_entry->h_aliases; *p; ++p) { - if (strchr(*p, '.')) - return *p; - } - } - return host_entry->h_name; -} - -/* uname() on FreeBSD is broken, because the 'nodename' buf is too small - * to hold a valid (leftmost) domain label. - */ -#if defined(HAVE_UNAME) && !defined(HOST_IS_FREEBSD) -#include <sys/utsname.h> -void sh_unix_localhost() -{ - struct utsname buf; - int i; - unsigned int ddot; - int len; - char * p; - char hostname[256]; - char numeric[SH_IP_BUF]; - char * canonical; - - - SL_ENTER(_("sh_unix_localhost")); - - (void) uname (&buf); - /* flawfinder: ignore */ /* ff bug, ff sees system() */ - sl_strlcpy (sh.host.system, buf.sysname, SH_MINIBUF); - sl_strlcpy (sh.host.release, buf.release, SH_MINIBUF); - sl_strlcpy (sh.host.machine, buf.machine, SH_MINIBUF); - - /* Workaround for cases where nodename could be - * a truncated FQDN. - */ - if (strlen(buf.nodename) == (sizeof(buf.nodename)-1)) - { - p = strchr(buf.nodename, '.'); - if (NULL != p) { - *p = '\0'; - sl_strlcpy(hostname, buf.nodename, 256); - } else { -#ifdef HAVE_GETHOSTNAME - if (0 != gethostname(hostname, 256)) - { - sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN, - _("nodename returned by uname may be truncated"), - _("sh_unix_localhost")); - sl_strlcpy (hostname, buf.nodename, 256); - } - else - { - hostname[255] = '\0'; - } -#else - sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN, - _("nodename returned by uname may be truncated"), - _("sh_unix_localhost")); - sl_strlcpy(hostname, buf.nodename, 256); -#endif - } - } - else - { - sl_strlcpy(hostname, buf.nodename, 256); - } - - canonical = sh_ipvx_canonical(hostname, numeric, sizeof(numeric)); - - if (canonical == NULL) - { - sl_strlcpy (sh.host.name, hostname, SH_PATHBUF); - sh_tolower (sh.host.name); - } - else - { - sl_strlcpy (sh.host.name, canonical, SH_PATHBUF); - SH_FREE(canonical); - } - - /* check whether it looks like a FQDN - */ - len = sl_strlen(sh.host.name); - ddot = 0; - for (i = 0; i < len; ++i) - if (sh.host.name[i] == '.') ++ddot; - - if (ddot == 0) - { - dlog(1, FIL__, __LINE__, - _("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"), - hostname, sh.host.name); - sl_strlcpy (sh.host.name, numeric, SH_PATHBUF); - SL_RET0(_("sh_unix_localhost")); - } - - if (sh_ipvx_is_numeric(sh.host.name)) - { - dlog(1, FIL__, __LINE__, - _("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"), - hostname, sh.host.name); - } - - SL_RET0(_("sh_unix_localhost")); -} - -#else - -/* - * --FreeBSD code - */ -#if defined(HAVE_UNAME) -#include <sys/utsname.h> -#endif -void sh_unix_localhost() -{ -#if defined(HAVE_UNAME) - struct utsname buf; -#endif - int i; - int ddot; - int len; - char hostname[1024]; - char numeric[SH_IP_BUF]; - char * canonical; - - SL_ENTER(_("sh_unix_localhost")); - -#if defined(HAVE_UNAME) - (void) uname (&buf); - /* flawfinder: ignore */ /* ff bug, ff sees system() */ - sl_strlcpy (sh.host.system, buf.sysname, SH_MINIBUF); - sl_strlcpy (sh.host.release, buf.release, SH_MINIBUF); - sl_strlcpy (sh.host.machine, buf.machine, SH_MINIBUF); -#endif - - (void) gethostname (hostname, 1024); - hostname[1023] = '\0'; - - canonical = sh_ipvx_canonical(hostname, numeric, sizeof(numeric)); - - if (canonical == NULL) - { - sl_strlcpy (sh.host.name, hostname, SH_PATHBUF); - sh_tolower (sh.host.name); - } - else - { - sl_strlcpy (sh.host.name, canonical, SH_PATHBUF); - SH_FREE(canonical); - } - - /* check whether it looks like a FQDN - */ - len = sl_strlen(sh.host.name); - ddot = 0; - for (i = 0; i < len; ++i) - if (sh.host.name[i] == '.') ++ddot; - if (ddot == 0) - { - dlog(1, FIL__, __LINE__, - _("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"), - hostname, sh.host.name); - sl_strlcpy (sh.host.name, numeric, SH_PATHBUF); - SL_RET0(_("sh_unix_localhost")); - } - - if (sh_ipvx_is_numeric(sh.host.name)) - { - dlog(1, FIL__, __LINE__, - _("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"), - hostname, sh.host.name); - } - - SL_RET0(_("sh_unix_localhost")); -} -#endif - - -void sh_unix_memlock() -{ - SL_ENTER(_("sh_unix_memlock")); - - /* do this before dropping privileges - */ -#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK) - if (skey->mlock_failed == S_FALSE) - { - if ( (-1) == sh_unix_mlock( FIL__, __LINE__, - (char *) skey, sizeof (sh_key_t)) ) - { - SH_MUTEX_LOCK_UNSAFE(mutex_skey); - skey->mlock_failed = S_TRUE; - SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); - } - } -#else - if (skey->mlock_failed == S_FALSE) - { - SH_MUTEX_LOCK_UNSAFE(mutex_skey); - skey->mlock_failed = S_TRUE; - SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); - } -#endif - - SL_RET0(_("sh_unix_memlock")); -} - -#ifdef SH_WITH_SERVER -char * chroot_dir = NULL; - -int sh_unix_set_chroot(const char * str) -{ - size_t len; - static int block = 0; - - if (block == 1) - return 0; - - if (str && *str == '/') - { - len = strlen(str) + 1; - chroot_dir = calloc(1,strlen(str) + 1); /* only once */ - if (!chroot_dir) - { - fprintf(stderr, _("%s: %d: Out of memory\n"), FIL__, __LINE__); - return 1; - } - sl_strlcpy(chroot_dir, str, len); - block = 1; - return 0; - } - return 1; -} - -int sh_unix_chroot(void) -{ - int status; - - if (chroot_dir != NULL) - { - status = retry_aud_chdir(FIL__, __LINE__, chroot_dir); - if ( (-1) == status ) - { - char errbuf[SH_ERRBUF_SIZE]; - status = errno; - sh_error_handle ((-1), FIL__, __LINE__, status, MSG_W_CHDIR, - sh_error_message (status, errbuf, sizeof(errbuf)), chroot_dir); - aud_exit(FIL__, __LINE__, EXIT_FAILURE); - } - /* flawfinder: ignore */ - return (chroot(chroot_dir)); - } - return 0; -} -/* #ifdef SH_WITH_SERVER */ -#else -int sh_unix_chroot(void) { return 0; } -#endif - -/* daemon mode - */ -static int block_setdeamon = 0; - -int sh_unix_setdeamon(const char * dummy) -{ - int res = 0; - - SL_ENTER(_("sh_unix_setdeamon")); - - if (block_setdeamon != 0) - SL_RETURN((0),_("sh_unix_setdeamon")); - - if (dummy == NULL) - sh.flag.isdaemon = S_TRUE; - else - res = sh_util_flagval (dummy, &sh.flag.isdaemon); - - if (sh.flag.opts == S_TRUE) - block_setdeamon = 1; - - SL_RETURN(res, _("sh_unix_setdeamon")); -} -#if defined(HAVE_LIBPRELUDE) -#include "sh_prelude.h" -#endif - -int sh_unix_setnodeamon(const char * dummy) -{ - int res = 0; - - SL_ENTER(_("sh_unix_setnodeamon")); - - if (block_setdeamon != 0) - SL_RETURN((0),_("sh_unix_setmodeamon")); - - if (dummy == NULL) - sh.flag.isdaemon = S_FALSE; - else - res = sh_util_flagval (dummy, &sh.flag.isdaemon); - - if (sh.flag.opts == S_TRUE) - block_setdeamon = 1; - - SL_RETURN(res, _("sh_unix_setnodeamon")); -} - -int sh_unix_init(int goDaemon) -{ - int status; - uid_t uid; - pid_t oldpid = getpid(); -#if defined(SH_WITH_SERVER) - extern int sh_socket_open_int (void); -#endif - char errbuf[SH_ERRBUF_SIZE]; - - extern void sh_kill_sub(); - - SL_ENTER(_("sh_unix_init")); - - /* fork twice, exit the parent process - */ - if (goDaemon == 1) { - - switch (aud_fork(FIL__, __LINE__)) { - case 0: break; /* child process continues */ - case -1: SL_RETURN((-1),_("sh_unix_init")); /* error */ - default: /* parent process exits */ - sh_kill_sub(); - aud__exit(FIL__, __LINE__, 0); - } - - /* Child processes do not inherit page locks across a fork. - * Error in next fork would return in this (?) thread of execution. - */ - sh_unix_memlock(); - - setsid(); /* should not fail */ - sh.pid = (UINT64) getpid(); - - switch (aud_fork(FIL__, __LINE__)) { - case 0: break; /* child process continues */ - case -1: SL_RETURN((-1),_("sh_unix_init")); /* error */ - default: /* parent process exits */ - sh_kill_sub(); - aud__exit(FIL__, __LINE__, 0); - } - - /* Child processes do not inherit page locks across a fork. - */ - sh_unix_memlock(); - sh.pid = (UINT64) getpid(); - - } else { - setsid(); /* should not fail */ - } - - /* set working directory - */ -#ifdef SH_PROFILE - status = 0; -#else - status = retry_aud_chdir(FIL__, __LINE__, "/"); -#endif - if ( (-1) == status ) - { - status = errno; - sh_error_handle ((-1), FIL__, __LINE__, status, MSG_W_CHDIR, - sh_error_message (status, errbuf, sizeof(errbuf)), "/"); - aud_exit(FIL__, __LINE__, EXIT_FAILURE); - } - - /* reset timers - */ - sh_unix_resettimer(); - - /* signal handlers - */ - sh_unix_resetsignals(); -#if defined(SCREW_IT_UP) - sh_sigtrap_prepare(); -#endif - sh_unix_siginstall (goDaemon); - - /* set file creation mask - */ - (void) umask (0); /* should not fail */ - - /* set resource limits to maximum, and - * core dump size to zero - */ - sh_unix_setlimits(); - - /* zero out the environment (like PATH='\0') - */ - sh_unix_zeroenv(); - - if (goDaemon == 1) - { - /* Close first tree file descriptors - */ - sl_close_fd (FIL__, __LINE__, 0); /* if running as daemon */ - sl_close_fd (FIL__, __LINE__, 1); /* if running as daemon */ - sl_close_fd (FIL__, __LINE__, 2); /* if running as daemon */ - - /* Enable full error logging - */ - sh_error_only_stderr (S_FALSE); - - /* open first three streams to /dev/null - */ - status = aud_open(FIL__, __LINE__, SL_NOPRIV, _("/dev/null"), O_RDWR, 0); - if (status < 0) - { - status = errno; - sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, - sh_error_message(status, errbuf, sizeof(errbuf)), _("open")); - aud_exit(FIL__, __LINE__, EXIT_FAILURE); - } - - status = retry_aud_dup(FIL__, __LINE__, 0); - if (status >= 0) - retry_aud_dup(FIL__, __LINE__, 0); - - if (status < 0) - { - status = errno; - sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, - sh_error_message(status, errbuf, sizeof(errbuf)), _("dup")); - aud_exit(FIL__, __LINE__, EXIT_FAILURE); - } - - sh_error_enable_unsafe (S_TRUE); -#if defined(HAVE_LIBPRELUDE) - sh_prelude_reset (); -#endif - - /* --- wait until parent has exited --- - */ - while (1 == 1) - { - errno = 0; - if (0 > aud_kill (FIL__, __LINE__, oldpid, 0) && errno == ESRCH) - { - break; - } - retry_msleep(0, 1); - } - - /* write PID file - */ - status = sh_unix_write_pid_file(); - if (status < 0) - { - sl_get_euid(&uid); - sh_error_handle ((-1), FIL__, __LINE__, status, MSG_PIDFILE, - (long) uid, sh.srvlog.alt); - aud_exit(FIL__, __LINE__, EXIT_FAILURE); - } -#if defined(SH_WITH_SERVER) - sh_socket_open_int (); -#endif - } - else - { - sh_error_enable_unsafe (S_TRUE); -#if defined(HAVE_LIBPRELUDE) - sh_prelude_reset (); -#endif -#if defined(SH_WITH_SERVER) - sh_socket_open_int (); -#endif - } - - /* chroot (this is a no-op if no chroot dir is specified - */ - status = sh_unix_chroot(); - if (status < 0) - { - status = errno; - sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, - sh_error_message(status, errbuf, sizeof(errbuf)), _("chroot")); - aud_exit(FIL__, __LINE__, EXIT_FAILURE); - } - - /* drop capabilities - */ - sl_drop_cap(); - - SL_RETURN((0),_("sh_unix_init")); -} - -/* --- run a command, securely --- */ - -int sh_unix_run_command (const char * str) -{ - pid_t pid; - char * arg[4]; - char * env[5]; - char * path = sh_util_strdup(_("/bin/sh")); - - int status = -1; - - arg[0] = sh_util_strdup(_("/bin/sh")); - arg[1] = sh_util_strdup(_("-c")); - arg[2] = sh_util_strdup(str); - arg[3] = NULL; - - env[0] = sh_util_strdup(_("PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/ucb")); - env[1] = sh_util_strdup(_("SHELL=/bin/sh")); - env[2] = sh_util_strdup(_("IFS= \t\n")); - if (getenv("TZ")) { /* flawfinder: ignore */ - char * tz = sh_util_strdup(getenv("TZ")); /* flawfinder: ignore */ - size_t tzlen = strlen(tz); - if (S_TRUE == sl_ok_adds (4, tzlen)) { - env[3] = SH_ALLOC(4+tzlen); - sl_strlcpy(env[3], "TZ=", 4); - sl_strlcat(env[3], tz , 4+tzlen); - } else { - env[3] = NULL; - } - } else { - env[3] = NULL; - } - env[4] = NULL; - - pid = fork(); - - if (pid == (pid_t)(-1)) - { - return -1; - } - - else if (pid == 0) /* child */ - { - memset(skey, 0, sizeof(sh_key_t)); - (void) umask(S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH); - sh_unix_closeall (3, -1, S_TRUE); /* in child process */ - execve(path, arg, env); - _exit(EXIT_FAILURE); - } - - else /* parent */ - { - int r; - - while((r = waitpid(pid, &status, WUNTRACED)) != pid && r != -1) ; - -#if !defined(USE_UNO) - if (r == -1 || !WIFEXITED(status)) - { - status = -1; - } - else - { - status = WEXITSTATUS(status); - } -#endif - } - - return status; -} - -/******************************************************** - * - * TIME - * - ********************************************************/ - -/* Figure out the time offset of the current timezone - * in a portable way. - */ -char * t_zone(const time_t * xx) -{ - struct tm aa; - struct tm bb; - - struct tm * aptr; - struct tm * bptr; - - int sign = 0; - int diff = 0; - int hh, mm; - static char tz[64]; - - SL_ENTER(_("t_zone")); - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GMTIME_R) - aptr = gmtime_r (xx, &aa); -#else - aptr = gmtime(xx); - if (aptr) - memcpy (&aa, aptr, sizeof(struct tm)); -#endif - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R) - bptr = localtime_r (xx, &bb); -#else - bptr = localtime(xx); - if (bptr) - memcpy (&bb, bptr, sizeof(struct tm)); -#endif - - if (bptr && aptr) - { - /* Check for datum wrap-around. - */ - if ((aa.tm_mday == 1) && (aa.tm_mday < bb.tm_mday) && (aa.tm_hour < bb.tm_hour)) - sign = ( 1); - else if (aa.tm_year < bb.tm_year) - sign = (-1); - else if (aa.tm_mon < bb.tm_mon) - sign = (-1); - else if (aa.tm_mday < bb.tm_mday) - sign = (-1); - else if (bb.tm_year < aa.tm_year) - sign = ( 1); - else if (bb.tm_mon < aa.tm_mon) - sign = ( 1); - else if (bb.tm_mday < aa.tm_mday) - sign = ( 1); - - diff = aa.tm_hour * 60 + aa.tm_min; - diff = (bb.tm_hour * 60 + bb.tm_min) - diff; - diff = diff - (sign * 24 * 60); /* datum wrap-around correction */ - hh = diff / 60; - mm = diff - (hh * 60); - sprintf (tz, _("%+03d%02d"), hh, mm); /* known to fit */ - } - else - { - sprintf (tz, _("%+03d%02d"), 0, 0); - } - SL_RETURN(tz, _("t_zone")); -} - -unsigned long sh_unix_longtime () -{ - return ((unsigned long)time(NULL)); -} - -#ifdef HAVE_GETTIMEOFDAY -unsigned long sh_unix_notime () -{ - struct timeval tv; - - gettimeofday (&tv, NULL); - - return ((unsigned long)(tv.tv_sec + tv.tv_usec * 10835 + getpid() + getppid())); - -} -#endif - -static int count_dev_time = 0; - -void reset_count_dev_time(void) -{ - count_dev_time = 0; - return; -} - -int sh_unix_settimeserver (const char * address) -{ - - SL_ENTER(_("sh_unix_settimeserver")); - - if (address != NULL && count_dev_time < 2 - && sl_strlen(address) < SH_PATHBUF) - { - if (count_dev_time == 0) - sl_strlcpy (sh.srvtime.name, address, SH_PATHBUF); - else - sl_strlcpy (sh.srvtime.alt, address, SH_PATHBUF); - - ++count_dev_time; - SL_RETURN((0), _("sh_unix_settimeserver")); - } - SL_RETURN((-1), _("sh_unix_settimeserver")); -} - - -#ifdef HAVE_NTIME -#define UNIXEPOCH 2208988800UL /* difference between Unix time and net time - * The UNIX EPOCH starts in 1970. - */ -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <ctype.h> -#endif - -/* Timeserver service. */ -/* define is missing on HP-UX 10.20 */ -#ifndef IPPORT_TIMESERVER -#define IPPORT_TIMESERVER 37 -#endif - -char * sh_unix_time (time_t thetime, char * buffer, size_t len) -{ - - int status; - char AsciiTime[81]; /* local time */ - time_t time_now; - struct tm * time_ptr; -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R) - struct tm time_tm; -#endif -#ifdef SH_USE_XML - static char deftime[] = N_("0000-00-00T00:00:00"); /* default time */ -#else - static char deftime[] = N_("[0000-00-00T00:00:00]"); /* default time */ -#endif - -#ifdef HAVE_NTIME - int fd; /* network file descriptor */ - u_char net_time[4]; /* remote time in network format */ - static int failerr = 0; /* no net time */ - int fail = 0; /* no net time */ - int errflag; - char errmsg[256]; - char error_call[SH_MINIBUF]; - int error_num; -#endif - - SL_ENTER(_("sh_unix_time")); - -#ifdef HAVE_NTIME - if (thetime == 0) - { - if (sh.srvtime.name[0] == '\0') - { - fail = 1; - (void) time (&time_now); - } - else /* have a timeserver address */ - { - /* don't call timeserver more than once per second */ - static time_t time_old = 0; - time_t time_new; - static time_t time_saved = 0; - (void) time (&time_new); - if ((time_new == time_old) && (time_saved != 0)) - { - time_now = time_saved; - goto end; - } - time_old = time_new; - - - fd = connect_port_2 (sh.srvtime.name, sh.srvtime.alt, - IPPORT_TIMESERVER, - error_call, &error_num, errmsg, sizeof(errmsg)); - if (fd >= 0) - { - if (4 != read_port (fd, (char *) net_time, 4, &errflag, 2)) - { - fail = 1; - sh_error_handle ((-1), FIL__, __LINE__, errflag, - MSG_E_NLOST, - _("time"), sh.srvtime.name); - } - sl_close_fd(FIL__, __LINE__, fd); - } - else - { - sh_error_handle ((-1), FIL__, __LINE__, error_num, - MSG_E_NET, errmsg, error_call, - _("time"), sh.srvtime.name); - fail = 1; - } - - if (fail == 0) - { - unsigned long ltmp; - UINT32 ttmp; - memcpy(&ttmp, net_time, sizeof(UINT32)); ltmp = ttmp; - time_now = ntohl(ltmp) - UNIXEPOCH; - time_saved = time_now; - - if (failerr == 1) { - failerr = 0; - sh_error_handle ((-1), FIL__, __LINE__, 0, - MSG_E_NEST, - _("time"), sh.srvtime.name); - } - } - else - { - (void) time (&time_now); - time_saved = 0; - - if (failerr == 0) - { - failerr = 1; - sh_error_handle ((-1), FIL__, __LINE__, errflag, - MSG_SRV_FAIL, - _("time"), sh.srvtime.name); - } - } - end: - ; /* 'label at end of compound statement' */ - } - } - else - { - time_now = thetime; - } - - /* #ifdef HAVE_NTIME */ -#else - - if (thetime == 0) - { - (void) time (&time_now); - } - else - { - time_now = thetime; - } - - /* #ifdef HAVE_NTIME */ -#endif - - if (time_now == (-1) ) - { - sl_strlcpy(buffer, _(deftime), len); - SL_RETURN(buffer, _("sh_unix_time")); - } - else - { -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R) - time_ptr = localtime_r (&time_now, &time_tm); -#else - time_ptr = localtime (&time_now); -#endif - } - if (time_ptr != NULL) - { - status = strftime (AsciiTime, sizeof(AsciiTime), -#ifdef SH_USE_XML - _("%Y-%m-%dT%H:%M:%S%%s"), -#else - _("[%Y-%m-%dT%H:%M:%S%%s]"), -#endif - time_ptr); - - sl_snprintf(buffer, len, AsciiTime, t_zone(&time_now)); - - if ( (status == 0) || (status == sizeof(AsciiTime)) ) - { - sl_strlcpy(buffer, _(deftime), len); - SL_RETURN( buffer, _("sh_unix_time")); - } - else - { - SL_RETURN(buffer, _("sh_unix_time")); - } - } - - /* last resort - */ - sl_strlcpy(buffer, _(deftime), len); - SL_RETURN( buffer, _("sh_unix_time")); -} - -static int sh_unix_use_localtime = S_FALSE; - -/* whether to use localtime for file timestamps in logs - */ -int sh_unix_uselocaltime (const char * c) -{ - int i; - SL_ENTER(_("sh_unix_uselocaltime")); - i = sh_util_flagval(c, &(sh_unix_use_localtime)); - - SL_RETURN(i, _("sh_unix_uselocaltime")); -} - -char * sh_unix_gmttime (time_t thetime, char * buffer, size_t len) -{ - - int status; - - struct tm * time_ptr; -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) - struct tm time_tm; -#endif - char AsciiTime[81]; /* GMT time */ -#ifdef SH_USE_XML - static char deftime[] = N_("0000-00-00T00:00:00"); /* default time */ -#else - static char deftime[] = N_("[0000-00-00T00:00:00]"); /* default time */ -#endif - - SL_ENTER(_("sh_unix_gmttime")); - - if (sh_unix_use_localtime == S_FALSE) - { -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GMTIME_R) - time_ptr = gmtime_r (&thetime, &time_tm); -#else - time_ptr = gmtime (&thetime); -#endif - } - else - { -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R) - time_ptr = localtime_r (&thetime, &time_tm); -#else - time_ptr = localtime (&thetime); -#endif - } - if (time_ptr != NULL) - { - status = strftime (AsciiTime, 80, -#ifdef SH_USE_XML - _("%Y-%m-%dT%H:%M:%S"), -#else - _("[%Y-%m-%dT%H:%M:%S]"), -#endif - time_ptr); - - if ( (status == 0) || (status == 80) ) - sl_strlcpy(buffer, _(deftime), len); - else - sl_strlcpy(buffer, AsciiTime, len); - SL_RETURN( buffer, _("sh_unix_gmttime")); - } - - /* last resort - */ - sl_strlcpy(buffer, _(deftime), len); - SL_RETURN( buffer, _("sh_unix_gmttime")); -} - - -char * sh_unix_getUIDdir (int level, uid_t uid, char * out, size_t len) -{ - struct passwd * tempres; - int status = 0; - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R) - struct passwd pwd; - char * buffer; -#endif - char errbuf[SH_ERRBUF_SIZE]; - - SL_ENTER(_("sh_unix_getUIDdir")); - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R) - buffer = SH_ALLOC(SH_PWBUF_SIZE); - sh_getpwuid_r(uid, &pwd, buffer, SH_PWBUF_SIZE, &tempres); -#else - errno = 0; - tempres = sh_getpwuid(uid); - status = errno; -#endif - - if (tempres == NULL) { - sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL, - sh_error_message(status, errbuf, sizeof(errbuf)), - _("getpwuid"), (long) uid, _("completely missing")); -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) - SH_FREE(buffer); -#endif - SL_RETURN( NULL, _("sh_unix_getUIDdir")); - } - - if (tempres->pw_dir != NULL) { - sl_strlcpy(out, tempres->pw_dir, len); -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) - SH_FREE(buffer); -#endif - SL_RETURN( out, _("sh_unix_getUIDdir")); - } else { - sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL, - sh_error_message(status, errbuf, sizeof(errbuf)), - _("getpwuid"), (long) uid, _("pw_dir")); -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) - SH_FREE(buffer); -#endif - SL_RETURN( NULL, _("sh_unix_getUIDdir")); - } -} - -/* ------------------- Caching ----------------*/ -#include "zAVLTree.h" - -#define CACHE_GID 0 -#define CACHE_UID 1 - -struct user_id { - char * name; - uid_t id; - struct user_id * next; -}; - -static struct user_id * uid_list = NULL; -static struct user_id * gid_list = NULL; - -SH_MUTEX_STATIC(mutex_cache, PTHREAD_MUTEX_INITIALIZER); - -static void sh_userid_free(struct user_id * item) -{ - while (item) - { - struct user_id * user = item; - item = item->next; - - SH_FREE(user->name); - SH_FREE(user); - } - return; -} - -void sh_userid_destroy () -{ - struct user_id * tmp_uid; - struct user_id * tmp_gid; - - SH_MUTEX_LOCK_UNSAFE(mutex_cache); - tmp_gid = gid_list; - gid_list = NULL; - tmp_uid = uid_list; - uid_list = NULL; - SH_MUTEX_UNLOCK_UNSAFE(mutex_cache); - - sh_userid_free(tmp_uid); - sh_userid_free(tmp_gid); - return; -} - -static void sh_userid_additem(struct user_id * list, struct user_id * item) -{ - if (list) - { - while (list && list->next) - list = list->next; - list->next = item; - } - return; -} - -static void sh_userid_add(uid_t id, char * username, int which) -{ - size_t len; - struct user_id * user = SH_ALLOC(sizeof(struct user_id)); - - if (username) - len = strlen(username) + 1; - else - len = 1; - - user->name = SH_ALLOC(len); - user->id = id; - if (username) - sl_strlcpy(user->name, username, len); - else - user->name[0] = '\0'; - user->next = NULL; - - SH_MUTEX_LOCK(mutex_cache); - if (which == CACHE_UID) - { - if (!uid_list) - uid_list = user; - else - sh_userid_additem(uid_list, user); - } - else - { - if (!gid_list) - gid_list = user; - else - sh_userid_additem(gid_list, user); - } - SH_MUTEX_UNLOCK(mutex_cache); - - return; -} - -static char * sh_userid_search(struct user_id * list, uid_t id) -{ - while (list) - { - if (list->id == id) - return list->name; - list = list->next; - } - return NULL; -} - -static char * sh_userid_get (uid_t id, int which, char * out, size_t len) -{ - char * user = NULL; - - SH_MUTEX_LOCK_UNSAFE(mutex_cache); - if (which == CACHE_UID) - user = sh_userid_search(uid_list, id); - else - user = sh_userid_search(gid_list, id); - if (user) - { - sl_strlcpy(out, user, len); - user = out; - } - SH_MUTEX_UNLOCK_UNSAFE(mutex_cache); - - return user; -} - -/* --------- end caching code --------- */ - -char * sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len) -{ - struct passwd * tempres; -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R) - struct passwd pwd; - char * buffer; -#endif - int status = 0; - char errbuf[SH_ERRBUF_SIZE]; - char * tmp; - - SL_ENTER(_("sh_unix_getUIDname")); - - tmp = sh_userid_get(uid, CACHE_UID, out, len); - - if (tmp) - { - if (tmp[0] != '\0') - { - SL_RETURN( out, _("sh_unix_getUIDname")); - } - else - { - SL_RETURN( NULL, _("sh_unix_getUIDname")); - } - } - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWUID_R) - buffer = SH_ALLOC(SH_PWBUF_SIZE); - sh_getpwuid_r(uid, &pwd, buffer, SH_PWBUF_SIZE, &tempres); -#else - errno = 0; - tempres = sh_getpwuid(uid); - status = errno; -#endif - - if (tempres == NULL) - { - sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL, - sh_error_message(status, errbuf, sizeof(errbuf)), - _("getpwuid"), (long) uid, _("completely missing")); -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) - SH_FREE(buffer); -#endif - sh_userid_add(uid, NULL, CACHE_UID); - SL_RETURN( NULL, _("sh_unix_getUIDname")); - } - - - if (tempres->pw_name != NULL) - { - - sl_strlcpy(out, tempres->pw_name, len); - sh_userid_add(uid, out, CACHE_UID); - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) - SH_FREE(buffer); -#endif - - SL_RETURN( out, _("sh_unix_getUIDname")); - } - else - { - sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL, - sh_error_message(status, errbuf, sizeof(errbuf)), - _("getpwuid"), (long) uid, _("pw_user")); -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) - SH_FREE(buffer); -#endif - SL_RETURN( NULL, _("sh_unix_getUIDname")); - } - /* notreached */ -} - -char * sh_unix_getGIDname (int level, gid_t gid, char * out, size_t len) -{ - struct group * tempres; - int status = 0; - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) - struct group grp; - char * buffer; -#endif - char errbuf[SH_ERRBUF_SIZE]; - char * tmp; - - SL_ENTER(_("sh_unix_getGIDname")); - - tmp = sh_userid_get((uid_t)gid, CACHE_GID, out, len); - - if (tmp) - { - if (tmp[0] != '\0') - { - SL_RETURN( out, _("sh_unix_getGIDname")); - } - else - { - SL_RETURN( NULL, _("sh_unix_getGIDname")); - } - } - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) - buffer = SH_ALLOC(SH_GRBUF_SIZE); - status = sh_getgrgid_r(gid, &grp, buffer, SH_GRBUF_SIZE, &tempres); -#else - errno = 0; - tempres = sh_getgrgid(gid); - status = errno; -#endif - - if (status == ERANGE) - { - static int seen = 0; - - if (seen == 0) - { - sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_GRNULL, - sh_error_message(status, errbuf, sizeof(errbuf)), - _("getgrgid"), (long) gid, _("line too long in group entry")); - ++seen; - } - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) - SH_FREE(buffer); -#endif - - sh_userid_add(gid, NULL, CACHE_GID); - SL_RETURN( NULL, _("sh_unix_getGIDname")); - } - - if (tempres == NULL) - { - sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_GRNULL, - sh_error_message(status, errbuf, sizeof(errbuf)), - _("getgrgid"), (long) gid, _("completely missing")); - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) - SH_FREE(buffer); -#endif - - sh_userid_add(gid, NULL, CACHE_GID); - SL_RETURN( NULL, _("sh_unix_getGIDname")); - } - - if (tempres->gr_name != NULL) - { - - sl_strlcpy(out, tempres->gr_name, len); - sh_userid_add((uid_t)gid, out, CACHE_GID); - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) - SH_FREE(buffer); -#endif - - SL_RETURN( out, _("sh_unix_getGIDname")); - } - else - { - sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_GRNULL, - sh_error_message(status, errbuf, sizeof(errbuf)), - _("getgrgid"), (long) gid, _("gr_name")); - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) - SH_FREE(buffer); -#endif - - SL_RETURN( NULL, _("sh_unix_getGIDname")); - } - /* notreached */ -} - -int sh_unix_getUser () -{ - char * p; - uid_t seuid, sruid; - char user[USER_MAX]; - char dir[SH_PATHBUF]; - - SL_ENTER(_("sh_unix_getUser")); - - seuid = geteuid(); - - sh.effective.uid = seuid; - - p = sh_unix_getUIDdir (SH_ERR_ERR, seuid, dir, sizeof(dir)); - - if (p == NULL) - SL_RETURN((-1), _("sh_unix_getUser")); - else - { - if (sl_strlen(p) >= SH_PATHBUF) { - sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_PWLONG, - _("getpwuid"), (long) seuid, _("pw_home")); - SL_RETURN((-1), _("sh_unix_getUser")); - } else { - sl_strlcpy ( sh.effective.home, p, SH_PATHBUF); - } - } - - sruid = getuid(); - - sh.real.uid = sruid; - - p = sh_unix_getUIDname (SH_ERR_ERR, sruid, user, sizeof(user)); - if (p == NULL) - SL_RETURN((-1), _("sh_unix_getUser")); - else - { - if (sl_strlen(p) >= USER_MAX) { - sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_PWLONG, - _("getpwuid"), (long) sruid, _("pw_user")); - SL_RETURN((-1), _("sh_unix_getUser")); - } else { - sl_strlcpy ( sh.real.user, p, USER_MAX); - } - } - - p = sh_unix_getUIDdir (SH_ERR_ERR, sruid, dir, sizeof(dir)); - - if (p == NULL) - SL_RETURN((-1), _("sh_unix_getUser")); - else - { - if (sl_strlen(p) >= SH_PATHBUF) { - sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_PWLONG, - _("getpwuid"), (long) sruid, _("pw_home")); - SL_RETURN((-1), _("sh_unix_getUser")); - } else { - sl_strlcpy ( sh.real.home, p, SH_PATHBUF); - } - } - - SL_RETURN((0), _("sh_unix_getUser")); - - /* notreached */ -} - - -int sh_unix_getline (SL_TICKET fd, char * line, int sizeofline) -{ - register int count; - register int n = 0; - char c; - - SL_ENTER(_("sh_unix_getline")); - - if (sizeofline < 2) { - line[0] = '\0'; - SL_RETURN((0), _("sh_unix_getline")); - } - - --sizeofline; - - while (n < sizeofline) { - - count = sl_read (fd, &c, 1); - - /* end of file - */ - if (count < 1) { - line[n] = '\0'; - n = -1; - break; - } - - if (/* c != '\0' && */ c != '\n') { - line[n] = c; - ++n; - } else if (c == '\n') { - if (n > 0) { - line[n] = '\0'; - break; - } else { - line[n] = '\n'; /* get newline only if only char on line */ - ++n; - line[n] = '\0'; - break; - } - } else { - line[n] = '\0'; - break; - } - - } - - - line[sizeofline] = '\0'; /* make sure line is terminated */ - SL_RETURN((n), _("sh_unix_getline")); -} - - -#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) - -/************************************************************** - * - * --- FILE INFO --- - * - **************************************************************/ - -#if (defined(__linux__) && (defined(HAVE_LINUX_EXT2_FS_H) || defined(HAVE_EXT2FS_EXT2_FS_H))) || defined(HAVE_STAT_FLAGS) - -#if defined(__linux__) - -/* --- Determine ext2fs file attributes. --- - */ -#include <sys/ioctl.h> -#if defined(HAVE_EXT2FS_EXT2_FS_H) -#include <ext2fs/ext2_fs.h> -#else -#include <linux/ext2_fs.h> -#endif - -/* __linux__ includes */ -#endif - -static -int sh_unix_getinfo_attr (char * name, - unsigned long * flags, - char * c_attr, - int fd, struct stat * buf) -{ - -/* TAKEN FROM: - * - * lsattr.c - List file attributes on an ext2 file system - * - * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr> - * Laboratoire MASI, Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * This file can be redistributed under the terms of the GNU General - * Public License - */ - -#ifdef HAVE_STAT_FLAGS - - SL_ENTER(_("sh_unix_getinfo_attr")); - - *flags = 0; - - /* cast to void to avoid compiler warning about unused parameters */ - (void) fd; - (void) name; - -#ifdef UF_NODUMP - if (buf->st_flags & UF_NODUMP) { - *flags |= UF_NODUMP; - c_attr[0] = 'd'; - } -#endif -#ifdef UF_IMMUTABLE - if (buf->st_flags & UF_IMMUTABLE) { - *flags |= UF_IMMUTABLE; - c_attr[1] = 'i'; - } -#endif -#ifdef UF_APPEND - if (buf->st_flags & UF_APPEND) { - *flags |= UF_APPEND; - c_attr[2] = 'a'; - } -#endif -#ifdef UF_NOUNLINK - if (buf->st_flags & UF_NOUNLINK) { - *flags |= UF_NOUNLINK; - c_attr[3] = 'u'; - } -#endif -#ifdef UF_OPAQUE - if (buf->st_flags & UF_OPAQUE) { - *flags |= UF_OPAQUE; - c_attr[4] = 'o'; - } -#endif -#ifdef SF_ARCHIVED - if (buf->st_flags & SF_ARCHIVED) { - *flags |= SF_ARCHIVED; - c_attr[5] = 'R'; - } - -#endif -#ifdef SF_IMMUTABLE - if (buf->st_flags & SF_IMMUTABLE) { - *flags |= SF_IMMUTABLE; - c_attr[6] = 'I'; - } -#endif -#ifdef SF_APPEND - if (buf->st_flags & SF_APPEND) { - *flags |= SF_APPEND; - c_attr[7] = 'A'; - } -#endif -#ifdef SF_NOUNLINK - if (buf->st_flags & SF_NOUNLINK) { - *flags |= SF_NOUNLINK; - c_attr[8] = 'U'; - } -#endif - - /* ! HAVE_STAT_FLAGS */ -#else - -#ifdef HAVE_EXT2_IOCTLS - int /* fd, */ r, f; - - SL_ENTER(_("sh_unix_getinfo_attr")); - - *flags = 0; - (void) buf; - - /* open() -> aud_open() R.Wichmann - fd = aud_open (FIL__, __LINE__, SL_YESPRIV, name, O_RDONLY|O_NONBLOCK, 0); - */ - - if (fd == -1 || name == NULL) - SL_RETURN(-1, _("sh_unix_getinfo_attr")); - - - r = ioctl (fd, EXT2_IOC_GETFLAGS, &f); - /* sl_close_fd (FIL__, __LINE__, fd); */ - - if (r == -1) - SL_RETURN(-1, _("sh_unix_getinfo_attr")); - - if (f == 0) - SL_RETURN(0, _("sh_unix_getinfo_attr")); - - *flags = f; - -/* ! HAVE_EXT2_IOCTLS */ -#else - - SL_ENTER(_("sh_unix_getinfo_attr")); - - *flags = 0; /* modified by R.Wichmann */ - -/* ! HAVE_EXT2_IOCTLS */ -#endif -/* - * END - * - * lsattr.c - List file attributes on an ext2 file system - */ - - if (*flags == 0) - goto theend; - -#ifdef EXT2_SECRM_FL - if ( (*flags & EXT2_SECRM_FL) != 0 ) c_attr[0] = 's'; -#endif -#ifdef EXT2_UNRM_FL - if ( (*flags & EXT2_UNRM_FL) != 0 ) c_attr[1] = 'u'; -#endif -#ifdef EXT2_SYNC_FL - if ( (*flags & EXT2_SYNC_FL) != 0 ) c_attr[2] = 'S'; -#endif -#ifdef EXT2_IMMUTABLE_FL - if ( (*flags & EXT2_IMMUTABLE_FL) != 0) c_attr[3] = 'i'; -#endif -#ifdef EXT2_APPEND_FL - if ( (*flags & EXT2_APPEND_FL) != 0 ) c_attr[4] = 'a'; -#endif -#ifdef EXT2_NODUMP_FL - if ( (*flags & EXT2_NODUMP_FL) != 0 ) c_attr[5] = 'd'; -#endif -#ifdef EXT2_NOATIME_FL - if ( (*flags & EXT2_NOATIME_FL) != 0) c_attr[6] = 'A'; -#endif -#ifdef EXT2_COMPR_FL - if ( (*flags & EXT2_COMPR_FL) != 0 ) c_attr[7] = 'c'; -#endif - -#ifdef EXT2_TOPDIR_FL - if ( (*flags & EXT2_TOPDIR_FL) != 0 ) c_attr[8] = 'T'; -#endif -#ifdef EXT2_DIRSYNC_FL - if ( (*flags & EXT2_DIRSYNC_FL) != 0 ) c_attr[9] = 'D'; -#endif -#ifdef EXT2_NOTAIL_FL - if ( (*flags & EXT2_NOTAIL_FL) != 0 ) c_attr[10] = 't'; -#endif -#ifdef EXT2_JOURNAL_DATA_FL - if ( (*flags & EXT2_JOURNAL_DATA_FL) != 0) c_attr[11] = 'j'; -#endif - - theend: - /* ext2 */ -#endif - - c_attr[12] = '\0'; - - SL_RETURN(0, _("sh_unix_getinfo_attr")); -} - -/* defined(__linux__) || defined(HAVE_STAT_FLAGS) */ -#endif - -/* determine file type - */ -static -int sh_unix_getinfo_type (struct stat * buf, - ShFileType * type, - char * c_mode) -{ - SL_ENTER(_("sh_unix_getinfo_type")); - - if ( S_ISREG(buf->st_mode) ) { - (*type) = SH_FILE_REGULAR; - c_mode[0] = '-'; - } - else if ( S_ISLNK(buf->st_mode) ) { - (*type) = SH_FILE_SYMLINK; - c_mode[0] = 'l'; - } - else if ( S_ISDIR(buf->st_mode) ) { - (*type) = SH_FILE_DIRECTORY; - c_mode[0] = 'd'; - } - else if ( S_ISCHR(buf->st_mode) ) { - (*type) = SH_FILE_CDEV; - c_mode[0] = 'c'; - } - else if ( S_ISBLK(buf->st_mode) ) { - (*type) = SH_FILE_BDEV; - c_mode[0] = 'b'; - } - else if ( S_ISFIFO(buf->st_mode) ) { - (*type) = SH_FILE_FIFO; - c_mode[0] = '|'; - } - else if ( S_ISSOCK(buf->st_mode) ) { - (*type) = SH_FILE_SOCKET; - c_mode[0] = 's'; - } - else if ( S_ISDOOR(buf->st_mode) ) { - (*type) = SH_FILE_DOOR; - c_mode[0] = 'D'; - } - else if ( S_ISPORT(buf->st_mode) ) { - (*type) = SH_FILE_PORT; - c_mode[0] = 'P'; - } - else { - (*type) = SH_FILE_UNKNOWN; - c_mode[0] = '?'; - } - - SL_RETURN(0, _("sh_unix_getinfo_type")); -} - -int sh_unix_get_ftype(char * fullpath) -{ - char c_mode[CMODE_SIZE]; - struct stat buf; - ShFileType type; - int res; - - SL_ENTER(_("sh_unix_get_ftype")); - - res = retry_lstat(FIL__, __LINE__, fullpath, &buf); - - if (res < 0) - SL_RETURN(SH_FILE_UNKNOWN, _("sh_unix_getinfo_type")); - - sh_unix_getinfo_type (&buf, &type, c_mode); - - SL_RETURN(type, _("sh_unix_get_ftype")); -} - - -static -int sh_unix_getinfo_mode (struct stat *buf, - unsigned int * mode, - char * c_mode) -{ - - SL_ENTER(_("sh_unix_getinfo_mode")); - - (*mode) = buf->st_mode; - - /* make 'ls'-like string */ - - if ( (buf->st_mode & S_IRUSR) != 0 ) c_mode[1] = 'r'; - if ( (buf->st_mode & S_IWUSR) != 0 ) c_mode[2] = 'w'; - if ( (buf->st_mode & S_IXUSR) != 0 ) { - if ((buf->st_mode & S_ISUID) != 0 ) c_mode[3] = 's'; - else c_mode[3] = 'x'; - } else { - if ((buf->st_mode & S_ISUID) != 0 ) c_mode[3] = 'S'; - } - - if ( (buf->st_mode & S_IRGRP) != 0 ) c_mode[4] = 'r'; - if ( (buf->st_mode & S_IWGRP) != 0 ) c_mode[5] = 'w'; - if ( (buf->st_mode & S_IXGRP) != 0 ) { - if ((buf->st_mode & S_ISGID) != 0 ) c_mode[6] = 's'; - else c_mode[6] = 'x'; - } else { - if ((buf->st_mode & S_ISGID) != 0 ) c_mode[6] = 'S'; - } - - if ( (buf->st_mode & S_IROTH) != 0 ) c_mode[7] = 'r'; - if ( (buf->st_mode & S_IWOTH) != 0 ) c_mode[8] = 'w'; -#ifdef S_ISVTX /* not POSIX */ - if ( (buf->st_mode & S_IXOTH) != 0 ) { - if ((buf->st_mode & S_ISVTX) != 0 ) c_mode[9] = 't'; - else c_mode[9] = 'x'; - } else { - if ((buf->st_mode & S_ISVTX) != 0 ) c_mode[9] = 'T'; - } -#else - if ( (buf->st_mode & S_IXOTH) != 0 ) c_mode[9] = 'x'; -#endif - - SL_RETURN(0, _("sh_unix_getinfo_mode")); -} - - -long IO_Limit = 0; - -void sh_unix_io_pause () -{ - long runtime; - float someval; - unsigned long sometime; - - if (IO_Limit == 0) - { - return; - } - else - { - runtime = (long) (time(NULL) - sh.statistics.time_start); - - if (runtime > 0 && (long)(sh.statistics.bytes_hashed/runtime) > IO_Limit) - { - someval = sh.statistics.bytes_hashed - (IO_Limit * runtime); - someval /= (float) IO_Limit; - if (someval < 1.0) - { - someval *= 1000; /* milliseconds in a second */ - sometime = (unsigned long) someval; - retry_msleep(0, sometime); - } - else - { - sometime = (unsigned long) someval; - retry_msleep (sometime, 0); - } - } - } - return; -} - -int sh_unix_set_io_limit (const char * c) -{ - long val; - - SL_ENTER(_("sh_unix_set_io_limit")); - - val = strtol (c, (char **)NULL, 10); - if (val < 0) - sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS, - _("set I/O limit"), c); - - val = (val < 0 ? 0 : val); - - IO_Limit = val * 1024; - SL_RETURN( 0, _("sh_unix_set_io_limit")); -} - -/* obtain file info - */ -extern int flag_err_debug; - -#include "sh_ignore.h" - -int sh_unix_checksum_size (char * filename, off_t size, int is_max_size, - char * fileHash, int alert_timeout, SL_TICKET fd, unsigned long mask) -{ - file_type * tmpFile; - int status; - - SL_ENTER(_("sh_unix_checksum_size")); - - tmpFile = SH_ALLOC(sizeof(file_type)); - tmpFile->link_path = NULL; - - if (sh.flag.checkSum != SH_CHECK_INIT) - { - /* lookup file in database */ - if (is_max_size == S_TRUE) { - status = sh_hash_get_it (filename, tmpFile, NULL); - if ((status != 0) || (tmpFile->size > size)) { - goto out; - } - } else { - tmpFile->size = size; - } - } - else - { - tmpFile->size = size; - } - - /* if last <= current get checksum */ - if (tmpFile->size <= size) - { - char hashbuf[KEYBUF_SIZE]; - UINT64 local_length = (UINT64) (tmpFile->size < 0 ? 0 : tmpFile->size); - if (sh.flag.opts == S_TRUE) sh_tiger_set_hashtype_mask(mask); - sl_strlcpy(fileHash, - sh_tiger_generic_hash (filename, fd, &(local_length), - alert_timeout, hashbuf, sizeof(hashbuf)), - KEY_LEN+1); - - /* return */ - if (tmpFile->link_path) SH_FREE(tmpFile->link_path); - SH_FREE(tmpFile); - SL_RETURN( 0, _("sh_unix_checksum_size")); - } - - out: - if (tmpFile->link_path) SH_FREE(tmpFile->link_path); - SH_FREE(tmpFile); - sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1); - SL_RETURN( -1, _("sh_unix_checksum_size")); -} - -/******************************************************** - * Search rotated logfile - */ -extern char * sh_rotated_log_search(const char * path, struct stat * buf); - -int sh_check_rotated_log (const char * path, - UINT64 old_size, UINT64 old_inode, const char * old_hash, unsigned long mask) -{ - struct stat obuf; - UINT64 length_nolim = TIGER_NOLIM; - int retval = S_FALSE; - - if (old_size != length_nolim) - { - char hashbuf[KEYBUF_SIZE]; - char * rotated_file; - - obuf.st_ino = old_inode; - rotated_file = sh_rotated_log_search(path, &obuf); - - if (rotated_file && (0 != strcmp(path, rotated_file))) - { - SL_TICKET fd = sl_open_fastread (FIL__, __LINE__, rotated_file, SL_YESPRIV); - if (!SL_ISERROR(fd)) - { - sh_unix_checksum_size (rotated_file, old_size, S_FALSE, - hashbuf, 120 /* alert_timeout */, fd, mask); - - sl_close(fd); - - if (strncmp (old_hash, hashbuf, KEY_LEN) == 0) { - retval = S_TRUE; - } - } - SH_FREE(rotated_file); - } - } - return retval; -} - - -int sh_unix_check_selinux = S_FALSE; -int sh_unix_check_acl = S_FALSE; - -#ifdef USE_ACL - -#include <sys/acl.h> -static char * sh_unix_getinfo_acl (char * path, int fd, struct stat * buf) -{ - /* system.posix_acl_access, system.posix_acl_default - */ - char * out = NULL; - char * collect = NULL; - char * tmp; - char * out_compact; - ssize_t len; - acl_t result; - - SL_ENTER(_("sh_unix_getinfo_acl")); - - result = (fd == -1) ? - acl_get_file (path, ACL_TYPE_ACCESS) : - acl_get_fd (fd); - - if (result) - { - out = acl_to_text (result, &len); - if (out && (len > 0)) { - out_compact = sh_util_acl_compact (out, len); - acl_free(out); - if (out_compact) - { - collect = sh_util_strconcat (_("acl_access:"), out_compact, NULL); - SH_FREE(out_compact); - } - } - acl_free(result); - } - - - if ( S_ISDIR(buf->st_mode) ) - { - result = acl_get_file (path, ACL_TYPE_DEFAULT); - - if (result) - { - out = acl_to_text (result, &len); - if (out && (len > 0)) { - out_compact = sh_util_acl_compact (out, len); - acl_free(out); - if (out_compact) { - if (collect) { - tmp = sh_util_strconcat (_("acl_default:"), - out_compact, ":", collect, NULL); - SH_FREE(collect); - } - else { - tmp = sh_util_strconcat (_("acl_default:"), out_compact, NULL); - } - SH_FREE(out_compact); - collect = tmp; - } - } - acl_free(result); - } - } - - SL_RETURN((collect),_("sh_unix_getinfo_acl")); -} -#endif - -#ifdef USE_XATTR - -#include <attr/xattr.h> -static char * sh_unix_getinfo_xattr_int (char * path, int fd, char * name) -{ - char * out = NULL; - char * tmp = NULL; - size_t size = 256; - ssize_t result; - - SL_ENTER(_("sh_unix_getinfo_xattr_int")); - - out = SH_ALLOC(size); - - result = (fd == -1) ? - lgetxattr (path, name, out, size-1) : - fgetxattr (fd, name, out, size-1); - - if (result == -1 && errno == ERANGE) - { - SH_FREE(out); - result = (fd == -1) ? - lgetxattr (path, name, NULL, 0) : - fgetxattr (fd, name, NULL, 0); - size = result + 1; - out = SH_ALLOC(size); - result = (fd == -1) ? - lgetxattr (path, name, out, size-1) : - fgetxattr (fd, name, out, size-1); - } - - if ((result > 0) && ((size_t)result < size)) - { - out[size-1] = '\0'; - tmp = out; - } - else - { - SH_FREE(out); - } - - SL_RETURN((tmp),_("sh_unix_getinfo_xattr_int")); -} - - -static char * sh_unix_getinfo_xattr (char * path, int fd, struct stat * buf) -{ - /* system.posix_acl_access, system.posix_acl_default, security.selinux - */ - char * tmp; - char * out = NULL; - char * collect = NULL; - - SL_ENTER(_("sh_unix_getinfo_xattr")); - -#ifdef USE_ACL - /* - * we need the acl_get_fd/acl_get_file functions, getxattr will only - * yield the raw bytes - */ - if (sh_unix_check_acl == S_TRUE) - { - out = sh_unix_getinfo_acl(path, fd, buf); - - if (out) - { - collect = out; - } - } -#else - (void) buf; -#endif - - if (sh_unix_check_selinux == S_TRUE) - { - out = sh_unix_getinfo_xattr_int(path, fd, _("security.selinux")); - - if (out) - { - if (collect) { - tmp = sh_util_strconcat(_("selinux:"), out, ":", collect, NULL); - SH_FREE(collect); - } - else { - tmp = sh_util_strconcat(_("selinux:"), out, NULL); - } - SH_FREE(out); - collect = tmp; - } - } - - SL_RETURN((collect),_("sh_unix_getinfo_xattr")); -} -#endif - -#ifdef USE_XATTR -int sh_unix_setcheckselinux (const char * c) -{ - int i; - SL_ENTER(_("sh_unix_setcheckselinux")); - i = sh_util_flagval(c, &(sh_unix_check_selinux)); - - SL_RETURN(i, _("sh_unix_setcheckselinux")); -} -#endif - -#ifdef USE_ACL -int sh_unix_setcheckacl (const char * c) -{ - int i; - SL_ENTER(_("sh_unix_setcheckacl")); - i = sh_util_flagval(c, &(sh_unix_check_acl)); - - SL_RETURN(i, _("sh_unix_setcheckacl")); -} -#endif - -#ifdef HAVE_LIBZ -#include <zlib.h> -#endif - - -static void * sh_dummy_filename; -static void * sh_dummy_tmp; -static void * sh_dummy_tmp2; - -int sh_unix_getinfo (int level, const char * filename, file_type * theFile, - char * fileHash, int policy) -{ - char timestr[81]; - long runtim; - struct stat buf; - struct stat lbuf; - struct stat fbuf; - volatile int stat_return; - volatile int stat_errno = 0; - - ShFileType type; - unsigned int mode; - char * tmp; - char * tmp2; - - char * linknamebuf; - volatile int linksize; - - extern int get_the_fd (SL_TICKET ticket); - - volatile SL_TICKET rval_open; - volatile int err_open = 0; - - volatile int fd; - volatile int fstat_return; - volatile int fstat_errno = 0; - volatile int try = 0; - - sh_string * content = NULL; - - time_t tend; - time_t tstart; - - - char * path = NULL; - - volatile int alert_timeout = 120; - - path = theFile->fullpath; - - SL_ENTER(_("sh_unix_getinfo")); - - if (!MODI_INITIALIZED(theFile->check_flags)) - { - tmp2 = sh_util_safe_name (theFile->fullpath); - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGPATH, - _("Uninitialized check mask"), _("sh_unix_getinfo"), - tmp2); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - SH_FREE(tmp2); - SL_RETURN((-1),_("sh_unix_getinfo")); - } - - /* Take the address to keep gcc from putting it into a register. - * Avoids the 'clobbered by longjmp' warning. - */ - sh_dummy_filename = (void *) &filename; - sh_dummy_tmp = (void *) &tmp; - sh_dummy_tmp2 = (void *) &tmp2; - - /* --- Stat the file, and get checksum. --- - */ - tstart = time(NULL); - - stat_return = retry_lstat (FIL__, __LINE__, - path /* theFile->fullpath */, &buf); - - if (stat_return) - stat_errno = errno; - - theFile->link_path = NULL; - - try_again: - - fd = -1; - fstat_return = -1; - rval_open = -1; - - if (stat_return == 0 && S_ISREG(buf.st_mode)) - { - rval_open = sl_open_fastread (FIL__, __LINE__, - path /* theFile->fullpath */, SL_YESPRIV); - if (SL_ISERROR(rval_open)) - { - char * stale = sl_check_stale(); - - if (stale) - { - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, err_open, MSG_E_SUBGEN, - stale, _("sh_unix_getinfo_open")); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - } - - if (errno == EBADF && try == 0) /* obsolete, but we keep this, just in case */ - { - ++try; - goto try_again; - } - err_open = errno; - } - - alert_timeout = 120; /* this is per 8K block now ! */ - - if (path[1] == 'p' && path[5] == '/' && path[2] == 'r' && - path[3] == 'o' && path[4] == 'c' && path[0] == '/') - { - /* seven is magic */ - alert_timeout = 7; - } - - fd = get_the_fd(rval_open); - } - - tend = time(NULL); - - /* An unprivileged user may slow lstat/open to a crawl - * with clever path/symlink setup - */ - if ((tend - tstart) > (time_t) /* 60 */ 6) - { - tmp2 = sh_util_safe_name (theFile->fullpath); - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_TOOLATE, - (long)(tend - tstart), tmp2); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - SH_FREE(tmp2); - } - - if (fd >= 0) - { - fstat_return = retry_fstat (FIL__, __LINE__, fd, &fbuf); - - if (fstat_return) - { - char * stale; - - fstat_errno = errno; - - stale = sl_check_stale(); - - if (stale) - { - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, fstat_errno, - MSG_E_SUBGEN, - stale, _("sh_unix_getinfo_fstat")); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - } - - if (try == 0) /* obsolete, but we keep this, just in case */ - { - ++try; - sl_close(rval_open); - goto try_again; - } - } - } - else - { - fd = -1; - } - - - /* --- case 1: lstat failed --- - */ - if (stat_return != 0) - { - stat_return = errno; - if (!SL_ISERROR(rval_open)) - sl_close(rval_open); - if (sh.flag.checkSum == SH_CHECK_INIT || - (sh_hash_have_it (theFile->fullpath) >= 0 && - (!SH_FFLAG_REPORTED_SET(theFile->file_reported)))) - { - if (S_FALSE == sh_ignore_chk_del(theFile->fullpath)) { - int flags = sh_hash_getflags (theFile->fullpath); - - if ((flags >= 0) && (flags & SH_FFLAG_ENOENT) == 0) { - char errbuf[SH_ERRBUF_SIZE]; - uid_t euid; - (void) sl_get_euid(&euid); - tmp2 = sh_util_safe_name (theFile->fullpath); - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle (level, FIL__, __LINE__, stat_return, MSG_FI_STAT, - _("lstat"), - sh_error_message (stat_errno, errbuf, sizeof(errbuf)), - (long) euid, - tmp2); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - SH_FREE(tmp2); - sh_hash_set_flag (theFile->fullpath, SH_FFLAG_ENOENT); - } - } - } - SL_RETURN((-1),_("sh_unix_getinfo")); - } - - /* --- case 2: not a regular file --- - */ - else if (! S_ISREG(buf.st_mode)) - { - if (fileHash != NULL) - sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1); - } - - /* --- case 3a: a regular file, fstat ok --- - */ - else if (fstat_return == 0 && - buf.st_mode == fbuf.st_mode && - buf.st_ino == fbuf.st_ino && - buf.st_uid == fbuf.st_uid && - buf.st_gid == fbuf.st_gid && - buf.st_dev == fbuf.st_dev ) - { - if (fileHash != NULL) - { - if ((theFile->check_flags & MODI_CHK) == 0 || - sh_restrict_this(theFile->fullpath, (UINT64) fbuf.st_size, - (UINT64) fbuf.st_mode, rval_open)) - { - sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1); - } - else if ((theFile->check_flags & MODI_PREL) != 0 && - S_TRUE == sh_prelink_iself(rval_open, fbuf.st_size, - alert_timeout, theFile->fullpath)) - { - if (0 != sh_prelink_run (theFile->fullpath, - fileHash, alert_timeout, theFile->check_flags)) - sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1); - } - else - { - char hashbuf[KEYBUF_SIZE]; - UINT64 length_current = TIGER_NOLIM; - - if (MODI_TXT_ENABLED(theFile->check_flags) && fbuf.st_size < (10 * SH_TXT_MAX)) - { - sl_init_content (rval_open, fbuf.st_size); - } - - if (sh.flag.opts == S_TRUE) sh_tiger_set_hashtype_mask(theFile->check_flags); - sl_strlcpy(fileHash, - sh_tiger_generic_hash (theFile->fullpath, - rval_open, &length_current, - alert_timeout, - hashbuf, sizeof(hashbuf)), - KEY_LEN+1); - - content = sl_get_content(rval_open); - content = sh_string_copy(content); - - if ((theFile->check_flags & MODI_SGROW) != 0) - { - /* Update size so it matches the one for which the checksum - has been computed */ - fbuf.st_size = length_current; - buf.st_size = fbuf.st_size; - sl_rewind(rval_open); - sh_unix_checksum_size (theFile->fullpath, length_current, S_TRUE, - &fileHash[KEY_LEN + 1], - alert_timeout, rval_open, theFile->check_flags); - } - } - } - } - - /* --- case 3b: a regular file, fstat ok, but different --- - */ - else if (fstat_return == 0 && S_ISREG(fbuf.st_mode)) - { - memcpy (&buf, &fbuf, sizeof( struct stat )); - - if (fileHash != NULL) - { - if ((theFile->check_flags & MODI_CHK) == 0 || - sh_restrict_this(theFile->fullpath, (UINT64) fbuf.st_size, - (UINT64) fbuf.st_mode, rval_open)) - { - sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1); - } - else if (policy == SH_LEVEL_PRELINK && - S_TRUE == sh_prelink_iself(rval_open, fbuf.st_size, - alert_timeout, theFile->fullpath)) - { - if (0 != sh_prelink_run (theFile->fullpath, - fileHash, alert_timeout, theFile->check_flags)) - sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1); - } - else - { - char hashbuf[KEYBUF_SIZE]; - UINT64 length_current = TIGER_NOLIM; - - if (MODI_TXT_ENABLED(theFile->check_flags) && fbuf.st_size < (10 * SH_TXT_MAX)) - { - sl_init_content (rval_open, fbuf.st_size); - } - - if (sh.flag.opts == S_TRUE) sh_tiger_set_hashtype_mask(theFile->check_flags); - sl_strlcpy(fileHash, - sh_tiger_generic_hash (theFile->fullpath, rval_open, - &length_current, - alert_timeout, - hashbuf, sizeof(hashbuf)), - KEY_LEN + 1); - - content = sl_get_content(rval_open); - content = sh_string_copy(content); - - if ((theFile->check_flags & MODI_SGROW) != 0) - { - /* Update size so it matches the one for which the checksum - has been computed */ - fbuf.st_size = length_current; - buf.st_size = fbuf.st_size; - sl_rewind(rval_open); - sh_unix_checksum_size (theFile->fullpath, length_current, S_TRUE, - &fileHash[KEY_LEN + 1], - alert_timeout, rval_open, theFile->check_flags); - } - } - } - } - - /* --- case 4: a regular file, fstat failed --- - */ - - else /* fstat_return != 0 or !S_ISREG(fbuf.st_mode) or open() failed */ - { - uid_t euid; - - if (fileHash != NULL) - sl_strlcpy(fileHash, SH_KEY_NULL, KEY_LEN+1); - - if ((theFile->check_flags & MODI_CHK) != 0) - { - tmp2 = sh_util_safe_name (theFile->fullpath); - - - if (fd >= 0 && fstat_return != 0) - { - char errbuf[SH_ERRBUF_SIZE]; - (void) sl_get_euid(&euid); - - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle (level, FIL__, __LINE__, stat_return, MSG_FI_STAT, - _("fstat"), - sh_error_message (fstat_errno, errbuf, sizeof(errbuf)), - (long) euid, - tmp2); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - } - else if (fd >= 0 && !S_ISREG(fbuf.st_mode)) - { - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle (level, FIL__, __LINE__, fstat_errno, - MSG_E_NOTREG, tmp2); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - } - else - { - char errbuf[SH_ERRBUF_SIZE]; - char errbuf2[SH_ERRBUF_SIZE]; - sl_strlcpy(errbuf, sl_error_string(rval_open), sizeof(errbuf)); - sh_error_message(err_open, errbuf2, sizeof(errbuf2)); - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle (level, FIL__, __LINE__, err_open, - MSG_E_READ, errbuf, errbuf2, tmp2); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - } - SH_FREE(tmp2); - } - } - - - /* --- Determine file type. --- - */ - memset (theFile->c_mode, '-', CMODE_SIZE-1); - theFile->c_mode[CMODE_SIZE-1] = '\0'; - - memset (theFile->link_c_mode, '-', CMODE_SIZE-1); - theFile->link_c_mode[CMODE_SIZE-1] = '\0'; - - sh_unix_getinfo_type (&buf, &type, theFile->c_mode); - theFile->type = type; - -#if defined(__linux__) || defined(HAVE_STAT_FLAGS) - - /* --- Determine file attributes. --- - */ - memset (theFile->c_attributes, '-', ATTRBUF_SIZE); - theFile->c_attributes[ATTRBUF_USED] = '\0'; - theFile->attributes = 0; - -#if (defined(__linux__) && (defined(HAVE_LINUX_EXT2_FS_H) || defined(HAVE_EXT2FS_EXT2_FS_H))) || defined(HAVE_STAT_FLAGS) - if (theFile->c_mode[0] != 'c' && theFile->c_mode[0] != 'b' && - theFile->c_mode[0] != 'l' ) - sh_unix_getinfo_attr(theFile->fullpath, - &theFile->attributes, theFile->c_attributes, - fd, &buf); -#endif -#endif - -#if defined(USE_XATTR) && defined(USE_ACL) - if (sh_unix_check_selinux == S_TRUE || sh_unix_check_acl == S_TRUE) - theFile->attr_string = sh_unix_getinfo_xattr (theFile->fullpath, fd, &buf); -#elif defined(USE_XATTR) - if (sh_unix_check_selinux == S_TRUE) - theFile->attr_string = sh_unix_getinfo_xattr (theFile->fullpath, fd, &buf); -#elif defined(USE_ACL) - if (sh_unix_check_acl == S_TRUE) - theFile->attr_string = sh_unix_getinfo_acl (theFile->fullpath, fd, &buf); -#else - theFile->attr_string = NULL; -#endif - - if (!SL_ISERROR(rval_open)) - sl_close(rval_open); - - - /* --- I/O limit. --- - */ - if (IO_Limit > 0) - { - runtim = (long) (time(NULL) - sh.statistics.time_start); - - if (runtim > 0 && (long)(sh.statistics.bytes_hashed/runtim) > IO_Limit) - retry_msleep(1, 0); - } - - /* --- Determine permissions. --- - */ - sh_unix_getinfo_mode (&buf, &mode, theFile->c_mode); - - /* --- Trivia. --- - */ - theFile->dev = buf.st_dev; - theFile->ino = buf.st_ino; - theFile->mode = buf.st_mode; - theFile->hardlinks = buf.st_nlink; - theFile->owner = buf.st_uid; - theFile->group = buf.st_gid; - theFile->rdev = buf.st_rdev; - theFile->size = buf.st_size; - theFile->blksize = (unsigned long) buf.st_blksize; - theFile->blocks = (unsigned long) buf.st_blocks; - theFile->atime = buf.st_atime; - theFile->mtime = buf.st_mtime; - theFile->ctime = buf.st_ctime; - - - /* --- Owner and group. --- - */ - - if (NULL == sh_unix_getGIDname(SH_ERR_ALL, buf.st_gid, theFile->c_group, GROUP_MAX+1)) { - - tmp2 = sh_util_safe_name (theFile->fullpath); - - if (policy == SH_LEVEL_ALLIGNORE) - { - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, ENOENT, - MSG_FI_NOGRP, - (long) buf.st_gid, tmp2); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - } - else - { - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, ENOENT, - MSG_FI_NOGRP, - (long) buf.st_gid, tmp2); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - } - SH_FREE(tmp2); - sl_snprintf(theFile->c_group, GROUP_MAX+1, "%d", (long) buf.st_gid); - } - - - if (NULL == sh_unix_getUIDname(SH_ERR_ALL, buf.st_uid, theFile->c_owner, USER_MAX+1)) { - - tmp2 = sh_util_safe_name (theFile->fullpath); - - if (policy == SH_LEVEL_ALLIGNORE) - { - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, ENOENT, - MSG_FI_NOUSR, - (long) buf.st_uid, tmp2); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - } - else - { - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle (ShDFLevel[SH_ERR_T_NAME], FIL__, __LINE__, ENOENT, - MSG_FI_NOUSR, - (long) buf.st_uid, tmp2); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - } - SH_FREE(tmp2); - sl_snprintf(theFile->c_owner, USER_MAX+1, "%d", (long) buf.st_uid); - } - - /* --- Output the file. --- - */ - if (flag_err_debug == S_TRUE) - { - tmp2 = sh_util_safe_name ((filename == NULL) ? - theFile->fullpath : filename); - (void) sh_unix_time(theFile->mtime, timestr, sizeof(timestr)); - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_LIST, - theFile->c_mode, - theFile->hardlinks, - theFile->c_owner, - theFile->c_group, - (unsigned long) theFile->size, - timestr, - tmp2); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - SH_FREE(tmp2); - } - - /* --- Check for links. --- - */ - if (theFile->c_mode[0] == 'l') - { - linknamebuf = SH_ALLOC(PATH_MAX); - - /* flawfinder: ignore */ - linksize = readlink (theFile->fullpath, linknamebuf, PATH_MAX-1); - - if (linksize < (PATH_MAX-1) && linksize >= 0) - linknamebuf[linksize] = '\0'; - else - linknamebuf[PATH_MAX-1] = '\0'; - - if (linksize < 0) - { - char errbuf[SH_ERRBUF_SIZE]; - linksize = errno; - tmp2 = sh_util_safe_name (theFile->fullpath); - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle (level, FIL__, __LINE__, linksize, MSG_FI_RDLNK, - sh_error_message (linksize, errbuf, sizeof(errbuf)), tmp2); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - SH_FREE(tmp2); - SH_FREE(linknamebuf); - theFile->link_path = sh_util_strdup("-"); - SL_RETURN((-1),_("sh_unix_getinfo")); - } - - if (linknamebuf[0] == '/') - { - theFile->link_path = sh_util_strdup (linknamebuf); - } - else - { - tmp = sh_util_dirname(theFile->fullpath); - if (tmp) { - theFile->link_path = SH_ALLOC(PATH_MAX); - sl_strlcpy (theFile->link_path, tmp, PATH_MAX); - SH_FREE(tmp); - } else { - theFile->link_path = SH_ALLOC(PATH_MAX); - theFile->link_path[0] = '\0'; - } - /* - * Only attach '/' if not root directory. Handle "//", which - * according to POSIX is implementation-defined, and may be - * different from "/" (however, three or more '/' will collapse - * to one). - */ - tmp = theFile->link_path; while (*tmp == '/') ++tmp; - if (*tmp != '\0') - { - sl_strlcat (theFile->link_path, "/", PATH_MAX); - } - sl_strlcat (theFile->link_path, linknamebuf, PATH_MAX); - } - - /* stat the link - */ - stat_return = retry_lstat (FIL__, __LINE__, theFile->link_path, &lbuf); - - /* check for error - */ - if (stat_return != 0) - { - stat_return = errno; - tmp = sh_util_safe_name (theFile->fullpath); - tmp2 = sh_util_safe_name (theFile->link_path); - if (stat_return != ENOENT) - { - uid_t euid; - char errbuf[SH_ERRBUF_SIZE]; - - (void) sl_get_euid(&euid); - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle (level, FIL__, __LINE__, stat_return, - MSG_FI_STAT, - _("lstat (link target)"), - sh_error_message (stat_return,errbuf, sizeof(errbuf)), - (long) euid, - tmp2); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - } - else - { - /* a dangling link -- everybody seems to have plenty of them - */ - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_DLNK, - tmp, tmp2); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - } - theFile->linkisok = BAD; - SH_FREE(tmp); - SH_FREE(tmp2); - SH_FREE(linknamebuf); - /* - * changed Tue Feb 10 16:16:13 CET 2004: - * add dangling symlinks into database - * SL_RETURN((-1),_("sh_unix_getinfo")); - */ - theFile->linkmode = 0; - SL_RETURN((0),_("sh_unix_getinfo")); - } - - theFile->linkisok = GOOD; - - - /* --- Determine file type. --- - */ - sh_unix_getinfo_type (&lbuf, &type, theFile->link_c_mode); - theFile->type = type; - - /* --- Determine permissions. --- - */ - sh_unix_getinfo_mode (&lbuf, &mode, theFile->link_c_mode); - theFile->linkmode = lbuf.st_mode; - - /* --- Output the link. --- - */ - if (theFile->linkisok == GOOD) - { - tmp2 = sh_util_safe_name (linknamebuf); - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_FI_LLNK, - theFile->link_c_mode, tmp2); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - SH_FREE(tmp2); - } - SH_FREE(linknamebuf); - } - else /* not a link, theFile->c_mode[0] != 'l' */ - { - if (content) - { -#ifdef HAVE_LIBZ - unsigned long clen; - unsigned char * compressed; -#ifdef HAVE_COMPRESSBOUND - clen = compressBound(sh_string_len(content)); -#else - if (sh_string_len(content) > 10*SH_TXT_MAX) - clen = SH_TXT_MAX; - else - clen = 13 + (int)(1.0001*sh_string_len(content)); -#endif - compressed = SH_ALLOC(clen); - if (Z_OK == compress(compressed, &clen, - (unsigned char *) sh_string_str(content), - sh_string_len(content))) - { - if (clen < SH_TXT_MAX) - { - sh_util_base64_enc_alloc (&(theFile->link_path), - (char *) compressed, clen); - } - else - { - char tmsg[128]; - char * tpath = sh_util_safe_name (theFile->fullpath); - sl_snprintf(tmsg, sizeof(tmsg), - _("compressed file too large (%lu bytes)"), - clen); - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, -1, - MSG_E_SUBGPATH, tmsg, - _("sh_unix_getinfo"), tpath); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - SH_FREE(tpath); - } - } - SH_FREE(compressed); -#endif - sh_string_destroy(&content); - } - } - SL_RETURN((0),_("sh_unix_getinfo")); -} - -/* #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) */ -#endif - -int sh_unix_unlock(char * lockfile, char * flag) -{ - int error = 0; - - SL_ENTER(_("sh_unix_unlock")); - - if (sh.flag.isdaemon == S_FALSE && flag == NULL) - SL_RETURN((0),_("sh_unix_unlock")); - - /* --- Logfile is not locked to us. --- - */ - if (sh.flag.islocked == BAD && flag != NULL) - SL_RETURN((-1),_("sh_unix_unlock")); - - /* --- Check whether the directory is secure. --- - */ - if (0 != tf_trust_check (lockfile, SL_YESPRIV)) - SL_RETURN((-1),_("sh_unix_unlock")); - - /* --- Delete the lock file. --- - */ - error = retry_aud_unlink (FIL__, __LINE__, lockfile); - - if (error == 0) - { - if (flag != NULL) - sh.flag.islocked = BAD; /* not locked anymore */ - } - else if (flag != NULL) - { - char errbuf[SH_ERRBUF_SIZE]; - error = errno; - sh_error_handle ((-1), FIL__, __LINE__, error, MSG_E_UNLNK, - sh_error_message(error, errbuf, sizeof(errbuf)), - lockfile); - SL_RETURN((-1),_("sh_unix_unlock")); - } - SL_RETURN((0),_("sh_unix_unlock")); -} - -int sh_unix_check_piddir (char * pidpath) -{ - static struct stat buf; - int status = 0; - char * pid_dir; - - SL_ENTER(_("sh_unix_check_piddir")); - - pid_dir = sh_util_dirname (pidpath); - - status = retry_lstat (FIL__, __LINE__, pid_dir, &buf); - - if (status < 0 && errno == ENOENT) - { - status = mkdir (pid_dir, 0777); - if (status < 0) - { - sh_error_handle ((-1), FIL__, __LINE__, status, - MSG_E_SUBGEN, - _("Cannot create PID directory"), - _("sh_unix_check_piddir")); - SH_FREE(pid_dir); - SL_RETURN((-1),_("sh_unix_check_piddir")); - } - } - else if (!S_ISDIR(buf.st_mode)) - { - sh_error_handle ((-1), FIL__, __LINE__, status, - MSG_E_SUBGEN, - _("Path of PID directory refers to a non-directory object"), - _("sh_unix_check_piddir")); - SH_FREE(pid_dir); - SL_RETURN((-1),_("sh_unix_check_piddir")); - } - SH_FREE(pid_dir); - SL_RETURN((0),_("sh_unix_check_piddir")); -} - -int sh_unix_lock (char * lockfile, char * flag) -{ - int filed; - int errnum; - char myPid[64]; - SL_TICKET fd; - extern int get_the_fd (SL_TICKET ticket); - - SL_ENTER(_("sh_unix_lock")); - - sprintf (myPid, "%ld\n", (long) sh.pid); /* known to fit */ - - if (flag == NULL) /* PID file, check for directory */ - { - if (0 != sh_unix_check_piddir (lockfile)) - { - SL_RETURN((-1),_("sh_unix_lock")); - } - } - - fd = sl_open_safe_rdwr (FIL__, __LINE__, - lockfile, SL_YESPRIV); /* fails if file exists */ - - if (!SL_ISERROR(fd)) - { - errnum = sl_write (fd, myPid, sl_strlen(myPid)); - filed = get_the_fd(fd); - fchmod (filed, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); - sl_close (fd); - - if (!SL_ISERROR(errnum)) - { - if (flag != NULL) - sh.flag.islocked = GOOD; - SL_RETURN((0),_("sh_unix_lock")); - } - } - - TPT((0, FIL__, __LINE__, _("msg=<open pid file failed>\n"))); - if (flag != NULL) - sh.flag.islocked = BAD; - SL_RETURN((-1),_("sh_unix_lock")); - - /* notreached */ -} - - -/* check whether file is locked - */ -int sh_unix_test_and_lock (char * filename, char * lockfile) -{ - static struct stat buf; - int status = 0; - - - SL_TICKET fd; - char line_in[128]; - - SL_ENTER(_("sh_unix_test_and_lock")); - - status = retry_lstat (FIL__, __LINE__, lockfile, &buf); - - /* --- No lock file found, try to lock. --- - */ - - if (status < 0 && errno == ENOENT) - { - if (0 == sh_unix_lock (lockfile, filename)) - { - if (filename != NULL) - sh.flag.islocked = GOOD; - SL_RETURN((0),_("sh_unix_test_and_lock")); - } - else - { - sh_error_handle ((-1), FIL__, __LINE__, status, - MSG_E_SUBGEN, - (filename == NULL) ? _("Cannot create PID file (1)") : _("Cannot create lock file (1)"), - _("sh_unix_test_and_lock")); - SL_RETURN((-1),_("sh_unix_test_and_lock")); - } - } - else if (status == 0 && buf.st_size == 0) - { - if (filename != NULL) - sh.flag.islocked = GOOD; - sh_unix_unlock (lockfile, filename); - if (filename != NULL) - sh.flag.islocked = BAD; - if (0 == sh_unix_lock (lockfile, filename)) - { - if (filename != NULL) - sh.flag.islocked = GOOD; - SL_RETURN((0),_("sh_unix_test_and_lock")); - } - else - { - sh_error_handle ((-1), FIL__, __LINE__, status, - MSG_E_SUBGEN, - (filename == NULL) ? _("Cannot create PID file (2)") : _("Cannot create lock file (2)"), - _("sh_unix_test_and_lock")); - SL_RETURN((-1),_("sh_unix_test_and_lock")); - } - } - - /* --- Check on lock. --- - */ - - if (status >= 0) - { - fd = sl_open_read (FIL__, __LINE__, lockfile, SL_YESPRIV); - if (SL_ISERROR(fd)) - sh_error_handle ((-1), FIL__, __LINE__, fd, - MSG_E_SUBGEN, - (filename == NULL) ? _("Cannot open PID file for read") : _("Cannot open lock file for read"), - _("sh_unix_test_and_lock")); - } - else - fd = -1; - - if (!SL_ISERROR(fd)) - { - /* read the PID in the lock file - */ - status = sl_read (fd, line_in, sizeof(line_in)); - line_in[sizeof(line_in)-1] = '\0'; - - /* convert to numeric - */ - if (status > 0) - { - errno = 0; - status = strtol(line_in, (char **)NULL, 10); - if (errno == ERANGE || status <= 0) - { - sh_error_handle ((-1), FIL__, __LINE__, status, - MSG_E_SUBGEN, - (filename == NULL) ? _("Bad PID in PID file") : _("Bad PID in lock file"), - _("sh_unix_test_and_lock")); - - status = -1; - } - } - else - { - sh_error_handle ((-1), FIL__, __LINE__, status, - MSG_E_SUBGEN, - (filename == NULL) ? _("Cannot read PID file") : _("Cannot read lock file"), - _("sh_unix_test_and_lock")); - } - sl_close(fd); - - if (status > 0 && (unsigned int) status == sh.pid) - { - if (filename != NULL) - sh.flag.islocked = GOOD; - SL_RETURN((0),_("sh_unix_test_and_lock")); - } - - - /* --- Check whether the process exists. --- - */ - if (status > 0) - { - errno = 0; - status = aud_kill (FIL__, __LINE__, status, 0); - - /* Does not exist, so remove the stale lock - * and create a new one. - */ - if (status < 0 && errno == ESRCH) - { - if (filename != NULL) - sh.flag.islocked = GOOD; - if (0 != sh_unix_unlock(lockfile, filename) && (filename !=NULL)) - sh.flag.islocked = BAD; - else - { - if (0 == sh_unix_lock (lockfile, filename)) - { - if (filename != NULL) - sh.flag.islocked = GOOD; - SL_RETURN((0),_("sh_unix_test_and_lock")); - } - else - { - sh_error_handle ((-1), FIL__, __LINE__, status, - MSG_E_SUBGEN, - (filename == NULL) ? _("Cannot create PID file (3)") : _("Cannot create lock file (3)"), - _("sh_unix_test_and_lock")); - } - if (filename != NULL) - sh.flag.islocked = BAD; - } - } - else - { - sh_error_handle ((-1), FIL__, __LINE__, status, - MSG_E_SUBGEN, - (filename == NULL) ? _("Cannot remove stale PID file, PID may be a running process") : _("Cannot remove stale lock file, PID may be a running process"), - _("sh_unix_test_and_lock")); - if (filename != NULL) - sh.flag.islocked = BAD; - } - } - } - SL_RETURN((-1),_("sh_unix_testlock")); -} - -/* write the PID file - */ -int sh_unix_write_pid_file() -{ - return sh_unix_test_and_lock(NULL, sh.srvlog.alt); -} - -/* write lock for filename - */ -int sh_unix_write_lock_file(char * filename) -{ - size_t len; - int res; - char * lockfile; - - if (filename == NULL) - return (-1); - - len = sl_strlen(filename); - if (sl_ok_adds(len, 6)) - len += 6; - lockfile = SH_ALLOC(len); - sl_strlcpy(lockfile, filename, len); - sl_strlcat(lockfile, _(".lock"), len); - res = sh_unix_test_and_lock(filename, lockfile); - SH_FREE(lockfile); - return res; -} - -/* rm lock for filename - */ -int sh_unix_rm_lock_file(char * filename) -{ - size_t len; - int res; - char * lockfile; - - if (filename == NULL) - return (-1); - - len = sl_strlen(filename); - if (sl_ok_adds(len, 6)) - len += 6; - lockfile = SH_ALLOC(len); - sl_strlcpy(lockfile, filename, len); - sl_strlcat(lockfile, _(".lock"), len); - - res = sh_unix_unlock(lockfile, filename); - SH_FREE(lockfile); - return res; -} - -/* rm lock for filename - */ -int sh_unix_rm_pid_file() -{ - return sh_unix_unlock(sh.srvlog.alt, NULL); -} - -/* Test whether file exists - */ -int sh_unix_file_exists(char * path) -{ - struct stat buf; - - SL_ENTER(_("sh_unix_file_exists")); - - if (0 == retry_lstat(FIL__, __LINE__, path, &buf)) - SL_RETURN( S_TRUE, _("sh_unix_file_exists")); - else - SL_RETURN( S_FALSE, _("sh_unix_file_exists")); -} - - -/* Test whether file exists, is a character device, and allows read - * access. - */ -int sh_unix_device_readable(int fd) -{ - struct stat buf; - - SL_ENTER(_("sh_unix_device_readable")); - - if (retry_fstat(FIL__, __LINE__, fd, &buf) == -1) - SL_RETURN( (-1), _("sh_unix_device_readable")); - else if ( S_ISCHR(buf.st_mode) && 0 != (S_IROTH & buf.st_mode) ) - SL_RETURN( (0), _("sh_unix_device_readable")); - else - SL_RETURN( (-1), _("sh_unix_device_readable")); -} - -static char preq[16]; - -/* return true if database is remote - */ -int file_is_remote () -{ - static int init = 0; - struct stat buf; - - SL_ENTER(_("file_is_remote")); - - if (init == 0) - { - sl_strlcpy(preq, _("REQ_FROM_SERVER"), 16); - ++init; - } - if (0 == sl_strncmp (sh.data.path, preq, 15)) - { - if (sh.data.path[15] != '\0') /* should be start of path */ - { - if (0 == stat(&(sh.data.path[15]), &buf)) - { - SL_RETURN( S_FALSE, _("file_is_remote")); - } - else - { - char * tmp = sh_util_safe_name (&(sh.data.path[15])); - sh_error_handle((-1), FIL__, __LINE__, S_FALSE, MSG_E_SUBGPATH, - _("No local baseline database at expected path"), - _("file_is_remote"), - tmp); - SH_FREE(tmp); - } - } - else - { - sh_error_handle((-1), FIL__, __LINE__, S_FALSE, MSG_E_SUBGEN, - _("No local baseline database path known"), - _("file_is_remote")); - } - SL_RETURN( S_TRUE, _("file_is_remote")); - } - SL_RETURN( S_FALSE, _("file_is_remote")); -} - -/* Return the path to the configuration/database file. - */ -char * file_path(char what, char flag) -{ - static int init = 0; - - SL_ENTER(_("file_path")); - - if (init == 0) - { - sl_strlcpy(preq, _("REQ_FROM_SERVER"), 16); - ++init; - } - - switch (what) - { - - case 'C': - if (0 == sl_strncmp (sh.conf.path, preq, 15)) - { -#if defined(SH_WITH_SERVER) - if (sh.flag.isserver == S_TRUE && sl_strlen(sh.conf.path) == 15) - SL_RETURN( NULL, _("file_path")); - if (sh.flag.isserver == S_TRUE) - SL_RETURN( &(sh.conf.path[15]), _("file_path")); -#endif - if (flag == 'R') - SL_RETURN( preq, _("file_path")); - if (flag == 'I') - { - if (sl_strlen(sh.conf.path) == 15) - SL_RETURN( NULL, _("file_path")); - else - SL_RETURN( &(sh.conf.path[15]), _("file_path")); - } - SL_RETURN ( preq, _("file_path")); - } - else - SL_RETURN( sh.conf.path, _("file_path")); - /* break; *//* unreachable */ - - case 'D': - if (0 == sl_strncmp (sh.data.path, preq, 15)) - { - if (flag == 'R') - SL_RETURN( preq, _("file_path")); - if (flag == 'W' && sl_strlen(sh.data.path) == 15) - SL_RETURN (NULL, _("file_path")); - if (flag == 'W') - SL_RETURN( &(sh.data.path[15]), _("file_path")); - } - else - SL_RETURN( sh.data.path, _("file_path")); - break; - - default: - SL_RETURN( NULL, _("file_path")); - } - - return NULL; /* notreached */ -} -/************************************************/ -/**** Mlock Utilities ****/ -/************************************************/ - -#include <limits.h> - -int sh_unix_pagesize() -{ - int pagesize = 4096; -#if defined(_SC_PAGESIZE) - pagesize = sysconf(_SC_PAGESIZE); -#elif defined(_SC_PAGE_SIZE) - pagesize = sysconf(_SC_PAGE_SIZE); -#elif defined(HAVE_GETPAGESIZE) - pagesize = getpagesize(); -#elif defined(PAGESIZE) - pagesize = PAGESIZE; -#endif - - return ((pagesize > 0) ? pagesize : 4096); -} - -typedef struct sh_page_lt { - unsigned long page_start; - int page_refcount; - char file[64]; - int line; - struct sh_page_lt * next; -} sh_page_l; - -sh_page_l * sh_page_locked = NULL; -volatile int page_locking = 0; - -unsigned long sh_unix_lookup_page (void * in_addr, size_t len, int * num_pages) -{ - int pagesize = sh_unix_pagesize(); - unsigned long addr = (unsigned long) in_addr; - - unsigned long pagebase; - unsigned long pagediff; - unsigned long pagenum = addr / pagesize; - - SL_ENTER(_("sh_unix_lookup_page")); -#if 0 - fprintf(stderr, "mlock: --> base %ld, pagenum: %ld\n", - addr, pagenum); -#endif - - /* address of first page - */ - pagebase = pagenum * pagesize; - - /* number of pages - */ - pagediff = (addr + len) - pagebase; - pagenum = pagediff / pagesize; - if (pagenum * pagesize < pagediff) - ++pagenum; - -#if 0 - fprintf(stderr, "mlock: --> pagebase %ld, pagediff %ld, (addr + len) %ld\n", - pagebase, pagediff, (addr + len)); -#endif - - *num_pages = pagenum; - SL_RETURN((pagebase), _("sh_unix_lookup_page")); -} - - -#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK) - -SH_MUTEX_STATIC(mutex_mlock,PTHREAD_MUTEX_INITIALIZER); - -int sh_unix_mlock (const char * file, int line, void * in_addr, size_t len) -{ - int num_pages; - int status = 0; - int pagesize; - sh_page_l * page_list; - unsigned long addr; -#ifdef TEST_MLOCK - int i = 0; -#endif - - SL_ENTER(_("sh_unix_mlock")); - - /* There's no cancellation point here, except if tracing is on - */ - SH_MUTEX_LOCK_UNSAFE(mutex_mlock); - - page_list = sh_page_locked; - - if (0 != page_locking) - { - status = -1; - goto exit_mlock; - } - - page_locking = 1; - - pagesize = sh_unix_pagesize(); - addr = sh_unix_lookup_page (in_addr, len, &num_pages); - -#ifdef TEST_MLOCK - fprintf(stderr, "mlock: addr %ld, base %ld, pages: %d, length %d\n", - (unsigned long) in_addr, addr, num_pages, len); -#endif - - /* increase refcount of locked pages - * addr is first page; num_pages is #(consecutive pages) to lock - */ - - while ((page_list != NULL) && (num_pages > 0)) - { -#ifdef TEST_MLOCK - fprintf(stderr, "mlock: check page %d: %ld [%d]\n", - i, page_list->page_start, page_list->page_refcount); -#endif - if (page_list->page_start == addr) - { - page_list->page_refcount += 1; - num_pages -= 1; - addr += pagesize; -#ifdef TEST_MLOCK - fprintf(stderr, "mlock: found page %d: %ld [%d], next page %ld\n", - i, page_list->page_start, page_list->page_refcount, addr); -#endif - } -#ifdef TEST_MLOCK - ++i; -#endif - page_list = page_list->next; - } - - /* mlock some more pages, if needed - */ - while (num_pages > 0) - { -#ifdef TEST_MLOCK - fprintf(stderr, "mlock: lock page %d: mlock %ld [num_pages %d]\n", - i, addr, num_pages); - ++i; -#endif - page_list = SH_ALLOC(sizeof(sh_page_l)); - page_list->page_start = addr; - page_list->page_refcount = 1; - sl_strlcpy(page_list->file, file, 64); - page_list->line = line; - status = mlock( (void *) addr, pagesize); - if (status != 0) - { -#ifdef TEST_MLOCK - char errbuf[SH_ERRBUF_SIZE]; - fprintf(stderr, "mlock: error: %s\n", - sh_error_message(errno, errbuf, sizeof(errbuf))); -#endif - SH_FREE(page_list); - page_locking = 0; - goto exit_mlock; - } - page_list->next = sh_page_locked; - sh_page_locked = page_list; - num_pages -= 1; - addr += pagesize; - } - page_locking = 0; - - exit_mlock: - SH_MUTEX_UNLOCK_UNSAFE(mutex_mlock); - - SL_RETURN((status), _("sh_unix_mlock")); -} -#else -int sh_unix_mlock (const char * file, int line, void * in_addr, size_t len) -{ - (void) file; (void) line; - (void) in_addr; (void) len; - return -1; -} -#endif - -#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK) -int sh_unix_munlock (void * in_addr, size_t len) -{ - int num_pages; - int unlocked; - int status; - int pagesize; - sh_page_l * page_list; - sh_page_l * page_last; - unsigned long addr; - - int test_count; - int test_status; - int test_pages; - -#ifdef TEST_MLOCK - int i = 0; -#endif - - SL_ENTER(_("sh_unix_munlock")); - - /* There's no cancellation point here, except if tracing is on - */ - SH_MUTEX_LOCK_UNSAFE(mutex_mlock); - - unlocked = 0; - status = 0; - page_list = sh_page_locked; - - if (0 != page_locking) - { - status = -1; - goto exit_munlock; - } - page_locking = 1; - - pagesize = sh_unix_pagesize(); - addr = sh_unix_lookup_page (in_addr, len, &num_pages); - -#ifdef TEST_MLOCK - fprintf(stderr, "munlock: in_addr %ld, addr %ld, pages: %d, length %d\n", - (unsigned long) in_addr, addr, num_pages, len); -#endif - - test_pages = num_pages; - - /* reduce refcount of locked pages - * addr is first page; num_pages is #(consecutive pages) to lock - */ - while ((page_list != NULL) && (num_pages > 0)) - { -#ifdef TEST_MLOCK - fprintf(stderr, "munlock: page %d: %ld [%d]\n", - i, page_list->page_start, page_list->page_refcount); -#endif - - test_status = 0; - for (test_count = 0; test_count < test_pages; ++test_count) - { - if (page_list->page_start == (addr + (test_count * pagesize))) - { - test_status = 1; - break; - } - } - - if (test_status == 1) - { - page_list->page_refcount -= 1; - if (page_list->page_refcount == 0) - { - status = munlock ( (void *) addr, pagesize); - ++unlocked; - } - num_pages -= 1; -#ifdef TEST_MLOCK - fprintf(stderr, - "munlock: page %d: %ld [refcount %d], refcount reduced\n", - i, page_list->page_start, page_list->page_refcount); -#endif - } -#ifdef TEST_MLOCK - ++i; -#endif - page_list = page_list->next; - } - -#ifdef TEST_MLOCK - i = 0; -#endif - - if (unlocked > 0) - { - page_list = sh_page_locked; - page_last = sh_page_locked; - - while ((page_list != NULL) && (unlocked > 0)) - { - if (page_list->page_refcount == 0) - { -#ifdef TEST_MLOCK - fprintf(stderr, "munlock: remove page %d: %ld [refcount %d]\n", - i, page_list->page_start, page_list->page_refcount); -#endif - if (page_last != page_list) - { - page_last->next = page_list->next; - SH_FREE(page_list); - page_list = page_last->next; - } - else - { - page_last = page_list->next; - if (page_list == sh_page_locked) - sh_page_locked = page_list->next; - SH_FREE(page_list); - page_list = page_last; - } - --unlocked; - } - else - { -#ifdef TEST_MLOCK - fprintf(stderr, "munlock: skip page %d: %ld [refcount %d]\n", - i, page_list->page_start, page_list->page_refcount); -#endif - - page_last = page_list; - page_list = page_list->next; - } -#ifdef TEST_MLOCK - ++i; -#endif - } - } - - page_locking = 0; - - exit_munlock: - SH_MUTEX_UNLOCK_UNSAFE(mutex_mlock); - SL_RETURN((status), _("sh_unix_munlock")); -} -#else -int sh_unix_munlock (void * in_addr, size_t len) -{ - (void) in_addr; (void) len; - return -1; -} -#endif - -int sh_unix_count_mlock() -{ - unsigned int i = 0; - char str[32][64]; - sh_page_l * page_list; - - SL_ENTER(_("sh_unix_count_mlock")); - -#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK) - /* There's no cancellation point here, except if tracing is on - */ - SH_MUTEX_LOCK_UNSAFE(mutex_mlock); -#endif - - page_list = sh_page_locked; - - while (page_list != NULL) - { -#ifdef WITH_TPT - if (i < 32) - sl_snprintf(str[i], 64, _("file: %s line: %d page: %d"), - page_list->file, page_list->line, i+1); -#endif - page_list = page_list->next; - ++i; - } - -#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK) - SH_MUTEX_UNLOCK_UNSAFE(mutex_mlock); -#endif - -#ifdef WITH_TPT - { - unsigned int j = 0; - while (j < i && j < 32) - { - sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, j, MSG_E_SUBGEN, - str[j], _("sh_unix_count_mlock")); - ++j; - } - } -#endif - - sl_snprintf(str[0], 64, _("%d pages locked"), i); - sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, i, MSG_E_SUBGEN, - str[0], _("sh_unix_count_mlock")); - SL_RETURN((i), _("sh_unix_count_mlock")); -} - -/************************************************/ -/************************************************/ -/**** Stealth Utilities ****/ -/************************************************/ -/************************************************/ -#ifdef SH_STEALTH - -void sh_unix_xor_code (char * str, int len) -{ - register int i; - - for (i = 0; i < len; ++i) str[i] ^= (char) XOR_CODE; - return; -} - -#if !defined(SH_STEALTH_MICRO) - - -int hideout_hex_block(SL_TICKET fd, unsigned char * str, int len, - unsigned long * bytes_read); -unsigned long first_hex_block(SL_TICKET fd, unsigned long * max); - -/* - * --- Get hidden data from a block of hex data. --- - */ -int sh_unix_getline_stealth (SL_TICKET fd, char * str, int len) -{ - int add_off = 0, llen; - static unsigned long off_data = 0; - static unsigned long max_data = 0; - static unsigned long bytes_read = 0; - static int stealth_init = BAD; - - SL_ENTER(_("sh_unix_getline_stealth")); - - if (str == NULL) - { - off_data = 0; - max_data = 0; - bytes_read = 0; - stealth_init = BAD; - SL_RETURN(0, _("sh_unix_getline_stealth")); - } - - /* --- Initialize. --- - */ - if (stealth_init == BAD) - { - off_data = first_hex_block(fd, &max_data); - if (off_data == 0) - { - dlog(1, FIL__, __LINE__, - _("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")); - sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_P_NODATA, - _("Stealth config file.")); - aud_exit (FIL__, __LINE__, EXIT_FAILURE); - } - stealth_init = GOOD; - max_data += off_data; - } - - /* --- Seek to proper position. --- - */ - if (bytes_read >= max_data || add_off < 0) - { - dlog(1, FIL__, __LINE__, - _("The capacity of the container image file for the stealth config file seems to be too small. Your config file is likely truncated.\n")); - sh_error_handle ((-1), FIL__, __LINE__, EIO, MSG_P_NODATA, - _("Stealth config file.")); - aud_exit (FIL__, __LINE__, EXIT_FAILURE); - } - sl_seek(fd, off_data); - - /* --- Read one line. --- - */ - add_off = hideout_hex_block(fd, (unsigned char *) str, len, &bytes_read); - off_data += add_off; - - llen = sl_strlen(str); - SL_RETURN(llen, _("sh_unix_getline_stealth")); -} - -int hideout_hex_block(SL_TICKET fd, unsigned char * str, int len, - unsigned long * bytes_read) -{ - - register int i, j, k; - unsigned char c, e; - register int num; - unsigned char mask[9] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; - unsigned long here = 0; - unsigned long retval = 0; - unsigned long bread = 0; - - SL_ENTER(_("hideout_hex_block")); - - ASSERT_RET((len > 1), _("len > 1"), (0)); - - --len; - - i = 0; - while (i < len) - { - for (j = 0; j < 8; ++j) - { - - /* --- Get a low byte, modify, read back. --- - */ - for (k = 0; k < 2; ++k) - { - /* -- Skip whitespace. --- - */ - c = ' '; - do { - do { - num = sl_read (fd, &c, 1); - } while (num == 0 && errno == EINTR); - if (num > 0) - ++here; - else if (num == 0) - SL_RETURN((0), _("hideout_hex_block")); - else - SL_RETURN((-1), _("hideout_hex_block")); - } while (c == '\n' || c == '\t' || c == '\r' || - c == ' '); - } - - - /* --- e is the value of the low byte. --- - */ - e = (unsigned char) sh_util_hexchar( c ); - if ((e & mask[7]) != 0) /* bit is set */ - str[i] |= mask[j]; - else /* bit is not set */ - str[i] &= ~mask[j]; - - bread += 1; - } - if (str[i] == '\n') break; - ++i; - } - - if (i != 0) - str[i] = '\0'; - else - str[i+1] = '\0'; /* keep newline and terminate */ - retval += here; - *bytes_read += (bread/8); - - SL_RETURN(retval, _("hideout_hex_block")); -} - -/* --- Get offset of first data block. --- - */ -unsigned long first_hex_block(SL_TICKET fd, unsigned long * max) -{ - unsigned int i; - long num = 1; - unsigned long lnum; - char c; - int nothex = 0; - unsigned long retval = 0; - unsigned int this_line = 0; - char theline[SH_BUFSIZE]; - - SL_ENTER(_("first_hex_block")); - - *max = 0; - - while (1) - { - theline[0] = '\0'; - this_line = 0; - c = '\0'; - while (c != '\n' && this_line < (sizeof(theline)-1)) - { - do { - num = sl_read (fd, &c, 1); - } while (num == 0 && errno == EINTR); - if (num > 0) - theline[this_line] = c; - else - SL_RETURN((0), _("first_hex_block")); - ++this_line; - } - theline[this_line] = '\0'; - - /* not only 'newline' */ - if (this_line > 60) - { - nothex = 0; - i = 0; - while (nothex == 0 && i < (this_line-1)) - { - if (! isxdigit((int)theline[i])) nothex = 1; - ++i; - } - if (nothex == 1) retval += this_line; - } - else - { - nothex = 1; - retval += this_line; - } - - if (nothex == 0) - { - *max = 0; - do { - do { - num = sl_read (fd, theline, SH_BUFSIZE); - } while (num == 0 && errno == EINTR); - if (num > 0) - { - lnum = (unsigned long) num; - for (i = 0; i < lnum; ++i) - { - c = theline[i]; - if (c == '\n' || c == '\t' || c == '\r' || c == ' ') - ; - else if (!isxdigit((int)c)) - break; - else - *max += 1; - } - } - } while (num > 0); - - *max /= 16; - SL_RETURN((retval), _("first_hex_block")); - } - - } - /* SL_RETURN((0), _("first_hex_block")); *//* unreachable */ -} - - /* if !defined(SH_STEALTH_MICRO) */ -#endif - - /* ifdef SH_STEALTH */ -#endif - -/* - * anti-debugger code - */ -#if defined(SCREW_IT_UP) - -#if defined(HAVE_PTHREAD) - -static pthread_key_t gSigtrapVariables_key; -static pthread_once_t gSigtrapVariables_key_once = PTHREAD_ONCE_INIT; - -static inline void make_gSigtrapVariables_key() -{ - (void) pthread_key_create(&gSigtrapVariables_key, free); -} - -struct sh_sigtrap_variables * sh_sigtrap_variables_get() -{ - void * ptr; - - (void) pthread_once(&gSigtrapVariables_key_once, make_gSigtrapVariables_key); - - ptr = pthread_getspecific(gSigtrapVariables_key); - if (ptr == NULL) { - ptr = calloc(1,sizeof(struct sh_sigtrap_variables)); - if (ptr == NULL) { - return NULL; - } - (void) pthread_setspecific(gSigtrapVariables_key, ptr); - } - - return (struct sh_sigtrap_variables *) ptr; -} - -/* !defined(HAVE_PTHREAD) */ -#else - -static struct sh_sigtrap_variables global_sigtrap_variables; -struct sh_sigtrap_variables * sh_sigtrap_variables_get() -{ - return &global_sigtrap_variables; -} - -#endif - -int sh_sigtrap_max_duration_set (const char * str) -{ - /* For security (prevent reloading with larger value) - * this value can only be set once. - */ - static int once = 0; - int i; - - SL_ENTER(_("sh_sigtrap_max_duration_set")); - - i = atoi (str); - - if (i >= 0 && once == 0) - { - sh.sigtrap_max_duration = i; - once = 1; - } - else - { - SL_RETURN ((-1), _("sh_sigtrap_max_duration_set")); - } - SL_RETURN( (0), _("sh_sigtrap_max_duration_set")); -} - -void sh_sigtrap_handler (int signum) -{ - struct sh_sigtrap_variables * sigtrap_variables; - sigtrap_variables = sh_sigtrap_variables_get(); - if (sigtrap_variables == NULL) { - /* Perhaps, it's better to not die, and to continue using Samhain, - even if this part does not work. */ - return; - } - -#ifdef HAVE_GETTIMEOFDAY - { - struct timeval tv; - long difftv; - - gettimeofday(&tv, NULL); - difftv = (tv.tv_sec - sigtrap_variables->save_tv.tv_sec) * 1000000 + - (tv.tv_usec - sigtrap_variables->save_tv.tv_usec); - if (difftv > sh.sigtrap_max_duration) - raise(SIGKILL); - } -#endif - - sigtrap_variables->not_traced = signum; - /* cppcheck-suppress memleak */ - return; -} -#endif diff --git a/src/bignum.c b/src/bignum.c index bd1bd71..8a622c1 100644 --- a/src/bignum.c +++ b/src/bignum.c @@ -174,7 +174,7 @@ init_digit_blocks(void) for (base = 2; base <= 36; base++) { - tmp = ((1 << (DIGIT_BITS - 1)) / base); + tmp = ((1U << (DIGIT_BITS - 1)) / base); maxdigit = tmp * 2; curdigit = 1; digcnt = 0; @@ -424,6 +424,7 @@ static int ucompare_digits(bignum *a, bignum *b) { DIGIT *a_ptr, *b_ptr; + int retval = 0; if (a->dgs_used == b->dgs_used) { @@ -436,12 +437,14 @@ ucompare_digits(bignum *a, bignum *b) } if (a_ptr < a->dp) { - return 0; + return retval; } else { - return (*a_ptr > *b_ptr) ? 1 : -1; + if (retval == 0) + retval = (*a_ptr > *b_ptr) ? 1 : -1; } + return retval; } return (a->dgs_used > b->dgs_used) ? 1 : -1; } diff --git a/src/cutest_sh_unix.c b/src/cutest_sh_unix.c index 57fb7e6..b4428cf 100644 --- a/src/cutest_sh_unix.c +++ b/src/cutest_sh_unix.c @@ -20,6 +20,7 @@ void Test_dnmalloc (CuTest *tc) { char * buf; char * area[256]; +#if !defined(USE_SYSTEM_MALLOC) && !defined(__clang__) /* test reuse of last freed chunk */ buf = malloc(1024); CuAssertPtrNotNull(tc, buf); @@ -27,7 +28,8 @@ void Test_dnmalloc (CuTest *tc) { area[0] = malloc(1024); CuAssertTrue(tc, buf == area[0]); free(area[0]); - +#endif + /* test realloc */ buf = malloc(16); CuAssertPtrNotNull(tc, buf); diff --git a/src/cutest_slib.c b/src/cutest_slib.c index 1e0e6c4..4350815 100644 --- a/src/cutest_slib.c +++ b/src/cutest_slib.c @@ -57,6 +57,27 @@ void Test_sl_snprintf (CuTest *tc) { CuAssertTrue(tc, input[4] == 'X'); } +void Test_sl_ts_strncmp (CuTest *tc) { + char one[64], two[64]; + int res; + + strcpy(one, "foo"); + strcpy(two, "foo"); + res = sl_ts_strncmp(one, two, 3); + CuAssertIntEquals(tc, 0, res); + + strcpy(one, "fox"); + strcpy(two, "foo"); + res = sl_ts_strncmp(one, two, 2); + CuAssertIntEquals(tc, 0, res); + + strcpy(one, "f9o"); + strcpy(two, "foo"); + res = sl_ts_strncmp(one, two, 3); + CuAssertTrue(tc, 0 != res); + +} + void Test_sl_strcasecmp (CuTest *tc) { char one[64], two[64]; int res; diff --git a/src/cutest_zAVLTree.c b/src/cutest_zAVLTree.c index 1201ac9..b616925 100644 --- a/src/cutest_zAVLTree.c +++ b/src/cutest_zAVLTree.c @@ -512,6 +512,7 @@ void Test_zAVLTree(CuTest *tc) { CuAssertTrue(tc, str == NULL); zAVL_string_reset(ztest_tree); + ztest_tree = NULL; str = zAVL_string_get(ztest_tree, "foo"); CuAssertTrue(tc, str == NULL); str = zAVL_string_get(ztest_tree, "bar"); diff --git a/src/depend-gen.c b/src/depend-gen.c index 586feee..c38b941 100644 --- a/src/depend-gen.c +++ b/src/depend-gen.c @@ -244,7 +244,7 @@ int main (int argc, char * argv[]) * EXCEPTIONS * **************************************************/ - if (0 == strcmp(p, "sh_gpg_chksum.h") || + if (0 == strcmp(p, "sh_sig_chksum.h") || 0 == strcmp(p, "sh_gpg_fp.h")) { /* fprintf(stderr, "Excluding %s\n", p); */ diff --git a/src/dnmalloc.c b/src/dnmalloc.c index 4ab3b9a..9f7bacc 100644 --- a/src/dnmalloc.c +++ b/src/dnmalloc.c @@ -164,7 +164,7 @@ * * HAVE_SYS_PARAM_H Define to #include <sys/param.h> (for pagesize) * - * HAVE_MALLOC_H Define to #include <malloc.h> (for struct mallinfo) + * HAVE_MALLOC_H Define to #include <malloc.h> (for struct mallinfo2) * * HAVE_FCNTL_H Define to #include <fcntl.h> * @@ -530,7 +530,7 @@ assert_handler_tp *dnmalloc_set_handler(assert_handler_tp *new) #define rEALLOc public_rEALLOc #define vALLOc public_vALLOc #define pVALLOc public_pVALLOc -#define mALLINFo public_mALLINFo +#define mALLINFo2 public_mALLINFo2 #define mALLOPt public_mALLOPt #define mTRIm public_mTRIm #define mSTATs public_mSTATs @@ -546,7 +546,7 @@ assert_handler_tp *dnmalloc_set_handler(assert_handler_tp *new) #define public_rEALLOc dlrealloc #define public_vALLOc dlvalloc #define public_pVALLOc dlpvalloc -#define public_mALLINFo dlmallinfo +#define public_mALLINFo2 dlmallinfo2 #define public_mALLOPt dlmallopt #define public_mTRIm dlmalloc_trim #define public_mSTATs dlmalloc_stats @@ -560,7 +560,7 @@ assert_handler_tp *dnmalloc_set_handler(assert_handler_tp *new) #define public_rEALLOc realloc #define public_vALLOc valloc #define public_pVALLOc pvalloc -#define public_mALLINFo mallinfo +#define public_mALLINFo2 mallinfo2 #define public_mALLOPt mallopt #define public_mTRIm malloc_trim #define public_mSTATs malloc_stats @@ -790,27 +790,27 @@ extern Void_t* sbrk(); #endif /* - This version of malloc supports the standard SVID/XPG mallinfo + This version of malloc supports the standard SVID/XPG mallinfo2 routine that returns a struct containing usage properties and statistics. It should work on any SVID/XPG compliant system that has - a /usr/include/malloc.h defining struct mallinfo. (If you'd like to + a /usr/include/malloc.h defining struct mallinfo2. (If you'd like to install such a thing yourself, cut out the preliminary declarations as described above and below and save them in a malloc.h file. But there's no compelling reason to bother to do this.) - The main declaration needed is the mallinfo struct that is returned - (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a + The main declaration needed is the mallinfo2 struct that is returned + (by-copy) by mallinfo2(). The SVID/XPG malloinfo2 struct contains a bunch of fields that are not even meaningful in this version of - malloc. These fields are are instead filled by mallinfo() with + malloc. These fields are are instead filled by mallinfo2() with other numbers that might be of interest. HAVE_MALLOC_H should be set if you have a /usr/include/malloc.h file that includes a declaration of struct - mallinfo. If so, it is included; else an SVID2/XPG2 compliant + mallinfo2. If so, it is included; else an SVID2/XPG2 compliant version is declared below. These must be precisely the same for - mallinfo() to work. The original SVID version of this struct, - defined on most systems with mallinfo, declares all fields as - ints. But some others define as unsigned long. If your system + mallinfo2() to work. The original SVID version of this struct, + defined on most systems with mallinfo2, declares all fields as + size_2. But some others define as unsigned long. If your system defines the fields using a type of different width than listed here, you must #include your system version and #define HAVE_MALLOC_H. @@ -821,23 +821,23 @@ extern Void_t* sbrk(); /* On *BSD, malloc.h is deprecated, and on some *BSD including * it may actually raise an error. */ -#if defined(HAVE_MALLOC_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__NetBSD__) +#if defined(HAVE_MALLOC_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 33) #include <malloc.h> #else -/* SVID2/XPG mallinfo structure */ - -struct mallinfo { - int arena; /* non-mmapped space allocated from system */ - int ordblks; /* number of free chunks */ - int smblks; /* number of fastbin blocks */ - int hblks; /* number of mmapped regions */ - int hblkhd; /* space in mmapped regions */ - int usmblks; /* maximum total allocated space */ - int fsmblks; /* space available in freed fastbin blocks */ - int uordblks; /* total allocated space */ - int fordblks; /* total free space */ - int keepcost; /* top-most, releasable (via malloc_trim) space */ +/* SVID2/XPG mallinfo2 structure */ + +struct mallinfo2 { + size_t arena; /* non-mmapped space allocated from system */ + size_t ordblks; /* number of free chunks */ + size_t smblks; /* number of fastbin blocks */ + size_t hblks; /* number of mmapped regions */ + size_t hblkhd; /* space in mmapped regions */ + size_t usmblks; /* maximum total allocated space */ + size_t fsmblks; /* space available in freed fastbin blocks */ + size_t uordblks; /* total allocated space */ + size_t fordblks; /* total free space */ + size_t keepcost; /* top-most, releasable (via malloc_trim) space */ }; /* @@ -1007,7 +1007,7 @@ int public_mALLOPt(); /* - mallinfo() + mallinfo2() Returns (by copy) a struct containing various summary statistics: arena: current total non-mmapped bytes allocated from system @@ -1030,9 +1030,9 @@ int public_mALLOPt(); thus be inaccurate. */ #if __STD_C -struct mallinfo public_mALLINFo(void); +struct mallinfo2 public_mALLINFo2(void); #else -struct mallinfo public_mALLINFo(); +struct mallinfo2 public_mALLINFo2(); #endif /* @@ -1114,7 +1114,7 @@ size_t public_mUSABLe(); (normally sbrk) outside of malloc. malloc_stats prints only the most commonly interesting statistics. - More information can be obtained by calling mallinfo. + More information can be obtained by calling mallinfo2. */ #if __STD_C @@ -1365,7 +1365,7 @@ static int mTRIm(size_t); static size_t mUSABLe(Void_t*); static void mSTATs(); static int mALLOPt(int, int); -static struct mallinfo mALLINFo(void); +static struct mallinfo2 mALLINFo2(void); #else static Void_t* mALLOc(); static void fREe(); @@ -1379,7 +1379,7 @@ static int mTRIm(); static size_t mUSABLe(); static void mSTATs(); static int mALLOPt(); -static struct mallinfo mALLINFo(); +static struct mallinfo2 mALLINFo2(); #endif /* @@ -1686,14 +1686,14 @@ void public_mSTATs() { } } -struct mallinfo public_mALLINFo() { - struct mallinfo m; +struct mallinfo2 public_mALLINFo2() { + struct mallinfo2 m; if (MALLOC_PREACTION == 0) { - m = mALLINFo(); + m = mALLINFo2(); (void) MALLOC_POSTACTION; return m; } else { - struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + struct mallinfo2 nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; return nm; } } @@ -5292,10 +5292,10 @@ DL_STATIC size_t mUSABLe(mem) Void_t* mem; ------------------------------ mallinfo ------------------------------ */ -DL_STATIC struct mallinfo mALLINFo() +DL_STATIC struct mallinfo2 mALLINFo2() { mstate av = get_malloc_state(); - struct mallinfo mi; + static struct mallinfo2 mi; unsigned int i; mbinptr b; chunkinfoptr p; @@ -5311,6 +5311,10 @@ DL_STATIC struct mallinfo mALLINFo() } check_malloc_state(); + if (!av || av->top == 0) { + return mi; + } + /* Account for top */ avail = chunksize(av->top); nblocks = 1; /* top always exists */ @@ -5356,19 +5360,18 @@ DL_STATIC struct mallinfo mALLINFo() DL_STATIC void mSTATs() { - struct mallinfo mi = mALLINFo(); + struct mallinfo2 mi = mALLINFo2(); fprintf(stderr, "hashtable = %10lu MB\n", (CHUNK_SIZE_T)(HASHTABLESIZE / (1024*1024))); fprintf(stderr, "max system bytes = %10lu\n", - (CHUNK_SIZE_T)(mi.usmblks)); + (CHUNK_SIZE_T)(mi.usmblks)); fprintf(stderr, "system bytes = %10lu (%10lu sbrked, %10lu mmaped)\n", - (CHUNK_SIZE_T)(mi.arena + mi.hblkhd), - (CHUNK_SIZE_T)(mi.arena), - (CHUNK_SIZE_T)(mi.hblkhd)); + (CHUNK_SIZE_T)(mi.arena + mi.hblkhd), + (CHUNK_SIZE_T)(mi.arena), + (CHUNK_SIZE_T)(mi.hblkhd)); fprintf(stderr, "in use bytes = %10lu\n", - (CHUNK_SIZE_T)(mi.uordblks + mi.hblkhd)); - + (CHUNK_SIZE_T)(mi.uordblks + mi.hblkhd)); } @@ -5521,7 +5524,7 @@ arc4_stir(void) struct { struct timeval tv1; struct timeval tv2; - u_int rnd[(128 - 2*sizeof(struct timeval)) / sizeof(u_int)]; + unsigned char rnd[(128 - 2*sizeof(struct timeval)) / sizeof(unsigned char)]; } rdat; #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) ssize_t sz = 0; diff --git a/src/samhain.c b/src/samhain.c index 43503cd..f5883e9 100644 --- a/src/samhain.c +++ b/src/samhain.c @@ -76,7 +76,7 @@ #include "sh_nmail.h" #include "sh_tiger.h" -#include "sh_gpg.h" +#include "sh_sig.h" #include "sh_mem.h" #include "sh_xfer.h" #include "sh_tools.h" @@ -347,7 +347,11 @@ void sh_init (void) sig_force_silent = 0; /* SIGTSTP */ sh_global_check_silent = 0; sh_load_delta_flag = 0; - strcpy ( sh_sig_msg, _("None")); + sh_sig_msg[4] = '\0'; + sh_sig_msg[3] = 'e'; + sh_sig_msg[2] = 'n'; + sh_sig_msg[1] = 'o'; + sh_sig_msg[0] = 'N'; #ifdef MKB_01 ErrFlag[1] |= (1 << 0); @@ -772,6 +776,7 @@ static void exit_handler(void) sh_files_delglobstack (); sh_hash_hashdelete(); sh_files_hle_reg (NULL); + (void) sh_ignore_clean (); /* * Only flush on exit if running as deamon. * Otherwise we couldn't run another instance @@ -833,7 +838,7 @@ static void exit_handler(void) if (sh.flag.isdaemon == S_TRUE) (void) sh_unix_rm_pid_file (); if (skey != NULL) - memset (skey, (int) '\0', sizeof(sh_key_t)); + memset (skey, 0, sizeof(sh_key_t)); /* --- Exit. --- */ @@ -876,6 +881,7 @@ static pid_t * procdirSamhain (void) if (NULL == (dp = opendir(_("/proc")))) { + /* cppcheck-suppress resourceLeak */ return NULL; } @@ -1374,7 +1380,7 @@ void do_reconf() } else { - sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_MOD_OK, + sh_error_handle ((-1), FIL__, __LINE__, status, MSG_MOD_OK, _(modList[modnum].name)); modList[modnum].initval = status; } @@ -1901,9 +1907,9 @@ int undef_main(int argc, char * argv[]) #if defined(SH_WITH_SERVER) && !defined(SH_WITH_CLIENT) -#if (defined(WITH_GPG) || defined(WITH_PGP)) +#if defined(WITH_GPG) /* log startup */ - sh_gpg_log_startup (); + sh_sig_log_startup (); #else sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_1H, sh.prg_name, (long) sh.real.uid, @@ -1924,9 +1930,9 @@ int undef_main(int argc, char * argv[]) if (sh.flag.checkSum == SH_CHECK_CHECK) { -#if (defined(WITH_GPG) || defined(WITH_PGP)) +#if defined(WITH_GPG) /* log startup */ - sh_gpg_log_startup (); + sh_sig_log_startup (); #else sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_2H, sh.prg_name, (long) sh.real.uid, @@ -1936,9 +1942,9 @@ int undef_main(int argc, char * argv[]) } else { -#if (defined(WITH_GPG) || defined(WITH_PGP)) +#if defined(WITH_GPG) /* log startup */ - sh_gpg_log_startup (); + sh_sig_log_startup (); #else sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_1H, sh.prg_name, (long) sh.real.uid, diff --git a/src/samhain_setpwd.c b/src/samhain_setpwd.c index e8de644..a12b801 100644 --- a/src/samhain_setpwd.c +++ b/src/samhain_setpwd.c @@ -245,8 +245,8 @@ int main (int argc, char * argv[]) char * newpwd = (char *) malloc(5 * 8 + 2); char * oldpwd = (char *) malloc(5 * 8 + 2); - memset (newpwd, '\0', 5 * 8 + 2); - memset (oldpwd, '\0', 5 * 8 + 2); + memset (newpwd, 0, 5 * 8 + 2); + memset (oldpwd, 0, 5 * 8 + 2); if (argc < 4) diff --git a/src/sh_audit.c b/src/sh_audit.c index 52d0c70..d4d4dd2 100644 --- a/src/sh_audit.c +++ b/src/sh_audit.c @@ -74,7 +74,7 @@ static int listRecords (auparse_state_t * au, struct recordState * state) sl_strlcpy(state->syscall, auparse_interpret_field(au), REC_SIZE_SYSCALL); if (auparse_find_field(au, _("success"))) - strncpy(state->success, auparse_interpret_field(au), REC_SIZE_SUCCESS); + sl_strlcpy(state->success, auparse_interpret_field(au), REC_SIZE_SUCCESS); if (auparse_find_field(au, "uid")) state->uid = auparse_get_field_int(au); @@ -147,7 +147,7 @@ static char * doAuparse (const char * file, time_t time, int tol, char * result, goto err; } - memset(&state, '\0', sizeof(state)); + memset(&state, 0, sizeof(state)); while (ausearch_next_event(au) == 1) { @@ -179,10 +179,13 @@ static char * doAuparse (const char * file, time_t time, int tol, char * result, if (0 == strcmp(state.success, "yes")) { + char time_str[81]; char * tmp_exe = sh_util_safe_name(state.exe); + + (void) sh_unix_gmttime (state.time, time_str, sizeof(time_str)); sl_snprintf(result, rsize, - _("time=%lu.%u, syscall=%s, auid=%u, uid=%u, gid=%u, euid=%u, egid=%u, fsuid=%u, fsgid=%u, exe=%s"), - (unsigned long) state.time, state.milli, + _("time=%lu.%u, timestamp=%s, syscall=%s, auid=%u, uid=%u, gid=%u, euid=%u, egid=%u, fsuid=%u, fsgid=%u, exe=%s"), + (unsigned long) state.time, state.milli, time_str, state.syscall, state.auid, state.uid, state.gid, state.euid, state.egid, state.fsuid, state.fsgid, tmp_exe); @@ -196,6 +199,23 @@ static char * doAuparse (const char * file, time_t time, int tol, char * result, return NULL; } +#define SH_AUDIT_DEF "wa" +static char sh_audit_flags[32] = SH_AUDIT_DEF; + +int sh_audit_set_flags(const char * str) +{ + if (!str || strlen(str) >= sizeof(sh_audit_flags)) + return -1; + sl_strlcpy(sh_audit_flags, str, sizeof(sh_audit_flags)); + return 0; +} +static void reset_audit_flags() +{ + sl_strlcpy(sh_audit_flags, SH_AUDIT_DEF, sizeof(sh_audit_flags)); + return; +} + + static int sh_audit_checkdaemon(); static int actl_pnum = -1; static char * actl_paths[4] = @@ -206,20 +226,23 @@ static char * actl_paths[4] = N_("/usr/bin/auditctl") }; +static char * getflags (char * file); /* Public function to fetch an audit record for path 'file', time 'time' * The 'result' array should be sized ~256 char. */ -char * sh_audit_fetch (char * file, time_t mtime, time_t ctime, char * result, size_t rsize) +char * sh_audit_fetch (char * file, time_t mtime, time_t ctime, time_t atime, char * result, size_t rsize) { - char * res = NULL; + char * res = NULL; + char * flags = getflags(file); if (sh_audit_checkdaemon() >= 0) { time_t new; - - if (mtime >= ctime) { new = mtime; } - else { new = ctime; } + + if (flags && (strchr(flags, 'r') || strchr(flags, 'x')) && atime >= ctime && atime >= mtime) { new = atime; } + else if (mtime >= ctime) { new = mtime; } + else { new = ctime; } res = doAuparse (file, new, 1, result, rsize, S_FALSE); @@ -250,6 +273,7 @@ void sh_audit_delete_all () sl_strlcpy(ctl, _(actl_paths[p]), sizeof(ctl)); sh_ext_system(ctl, ctl, "-D", "-k", _("samhain"), NULL); } + reset_audit_flags(); return; } @@ -262,7 +286,7 @@ static int sh_audit_isdir(const char * file) return S_FALSE; } -static void sh_audit_mark_int (const char * file) +static void sh_audit_mark_int (const char * file, const char * flags) { static int flushRules = 0; @@ -285,10 +309,10 @@ static void sh_audit_mark_int (const char * file) char a1[32]; char a2[32]; char a3[32]; + char a4[32]; - sl_snprintf(command, len, _("%s -w %s -p wa -k samhain"), - _(actl_paths[p]), - file); + sl_snprintf(command, len, _("%s -w %s -p %s -k samhain"), + _(actl_paths[p]), file, flags); safe = sh_util_safe_name_keepspace(command); sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, @@ -302,7 +326,8 @@ static void sh_audit_mark_int (const char * file) sl_strlcpy(command, file, len); sl_strlcpy(a3, _("samhain"), sizeof(a3)); - sh_ext_system(ctl, ctl, "-w", command, "-p", "wa", "-k", a3, NULL); + sl_strlcpy(a4, flags, sizeof(a4)); + sh_ext_system(ctl, ctl, "-w", command, "-p", a4, "-k", a3, NULL); /* Placing a watch on a directory will not place a watch on the * directory inode, so we do this explicitely. @@ -318,7 +343,8 @@ static void sh_audit_mark_int (const char * file) sl_strlcpy(command, _("path="), len); sl_strlcat(command, file, len); sl_strlcpy(a1, _("always,exit"), sizeof(a1)); - sl_strlcpy(a2, _("perm=wa"), sizeof(a2)); + sl_strlcpy(a2, _("perm="), sizeof(a2)); + sl_strlcat(a2, flags, sizeof(a2)); sh_ext_system(ctl, ctl, "-a", a1, "-F", command, "-F", a2, "-k", a3, NULL); } SH_FREE(command); @@ -326,12 +352,47 @@ static void sh_audit_mark_int (const char * file) return; } +#define SH_AU_FLAGS_SIZ 32 struct aud_list { char * file; + char flags[SH_AU_FLAGS_SIZ]; struct aud_list * next; }; struct aud_list * mark_these = NULL; +static int marked_committed = 0; + +static void delete_listofmarked() +{ + struct aud_list * tmp; + struct aud_list * this = mark_these; + + mark_these = NULL; + + while (this) + { + tmp = this; + this = this->next; + + SH_FREE(tmp->file); + SH_FREE(tmp); + } + marked_committed = 0; +} + +static char * getflags (char * file) +{ + struct aud_list * this = mark_these; + + while (this) + { + if (0 == strcmp(file, this->file)) + return this->flags; + this = this->next; + } + /* no explicit rule for this file */ + return NULL; +} static void add_this (char * file) { @@ -339,8 +400,12 @@ static void add_this (char * file) size_t len = strlen(file); this->file = sh_util_strdup(file); + + /* strip trailing '/' */ if ((len > 1) && (file[len-1] == '/')) this->file[len-1] = '\0'; + + sl_strlcpy(this->flags, sh_audit_flags, SH_AU_FLAGS_SIZ); this->next = mark_these; mark_these = this; @@ -349,44 +414,50 @@ static void add_this (char * file) /* Check whether it is already covered by a higher directory */ -static int test_exchange (struct aud_list * this, char * file) +static int test_exchange (struct aud_list * this, const char * file) { size_t len0 = sl_strlen(this->file); size_t len1 = sl_strlen(file); int ret = -1; + if (!file || !this || !this->file) + return 0; + if (len0 == len1) { return strcmp(this->file, file); } else { - char * s0 = SH_ALLOC(len0 + 2); - char * s1 = SH_ALLOC(len1 + 2); - - sl_strlcpy(s0, this->file, len0 + 2); - sl_strlcpy(s1, file, len1 + 2); - - if (s0 < s1) - { - sl_strlcat(s0, "/", len0 + 2); - ret = strncmp(s0, s1, len0 + 1); - } - else - { - sl_strlcat(s1, "/", len1 + 2); - if (0 == strncmp(s0, s1, len1 + 1)) - { - size_t len = strlen(file); - SH_FREE(this->file); - this->file = sh_util_strdup(file); - if ((len > 1) && (file[len-1] == '/')) - this->file[len-1] = '\0'; - ret = 0; - } - } - SH_FREE(s0); - SH_FREE(s1); + if (0 == strcmp(this->flags, sh_audit_flags)) + { + char * s0 = SH_ALLOC(len0 + 2); + char * s1 = SH_ALLOC(len1 + 2); + + sl_strlcpy(s0, this->file, len0 + 2); + sl_strlcpy(s1, file, len1 + 2); + + if (s0 < s1) + { + sl_strlcat(s0, "/", len0 + 2); + ret = strncmp(s0, s1, len0 + 1); + } + else + { + sl_strlcat(s1, "/", len1 + 2); + if (0 == strncmp(s0, s1, len1 + 1)) + { + size_t len = strlen(file); + SH_FREE(this->file); + this->file = sh_util_strdup(file); + if ((len > 1) && (file[len-1] == '/')) + this->file[len-1] = '\0'; + ret = 0; + } + } + SH_FREE(s0); + SH_FREE(s1); + } } return ret; @@ -396,13 +467,18 @@ static int test_exchange (struct aud_list * this, char * file) */ void sh_audit_mark (char * file) { - struct aud_list * this = mark_these; + struct aud_list * this; + if (marked_committed != 0) + delete_listofmarked(); + if (!mark_these) { add_this (file); return; } + this = mark_these; + while (this) { /* Check whether it is already covered by a higher @@ -410,6 +486,7 @@ void sh_audit_mark (char * file) */ if (0 == test_exchange(this, file)) return; + this = this->next; } @@ -419,20 +496,14 @@ void sh_audit_mark (char * file) void sh_audit_commit () { - struct aud_list * next; struct aud_list * this = mark_these; - mark_these = NULL; - while (this) { - sh_audit_mark_int (this->file); - next = this->next; - SH_FREE(this->file); - SH_FREE(this); - this = next; + sh_audit_mark_int (this->file, this->flags); + this = this->next; } - + marked_committed = 1; } static int sh_audit_checkdaemon() @@ -537,11 +608,12 @@ static int sh_audit_checkdaemon() /* HAVE_AUPARSE_H */ #else -char * sh_audit_fetch (char * file, time_t mtime, time_t ctime, char * result, size_t rsize) +char * sh_audit_fetch (char * file, time_t mtime, time_t ctime, time_t atime, char * result, size_t rsize) { (void) file; (void) mtime; (void) ctime; + (void) atime; (void) result; (void) rsize; @@ -563,6 +635,11 @@ void sh_audit_commit () { return; } +int sh_audit_set_flags(const char * str) +{ + (void) str; + return -1; +} #endif /* client || standalone */ diff --git a/src/sh_calls.c b/src/sh_calls.c index 2269836..cf4c4c5 100644 --- a/src/sh_calls.c +++ b/src/sh_calls.c @@ -50,7 +50,6 @@ #include "samhain.h" #include "sh_error.h" -#include "sh_calls.h" #include "sh_ipvx.h" #include "sh_sub.h" #include "sh_utils.h" @@ -533,8 +532,8 @@ long int retry_msleep (int sec, int millisec) ***************************************************/ long int retry_aud_execve (const char * file, int line, - const char *dateiname, char * argv[], - char * envp[]) + const char *dateiname, char *const argv[], + char *const envp[]) { uid_t a = geteuid(); gid_t b = getegid(); @@ -736,6 +735,7 @@ long int aud_open_noatime (const char * file, int line, int privs, if ((val_return < 0) && (*o_noatime != 0)) { + /* cppcheck-suppress resourceLeak */ val_return = open (pathname, flags, mode); if (val_return >= 0) *o_noatime = 0; @@ -932,7 +932,7 @@ int aud_setgid (const char * file, int line, gid_t gid) SL_RETURN(i, _("aud_setgid")); } -int aud_pipe (const char * file, int line, int * modus) +int aud_pipe (const char * file, int line, int modus[2]) { int error; int i = pipe (modus); diff --git a/src/sh_cat.c b/src/sh_cat.c index dfffae1..9328543 100644 --- a/src/sh_cat.c +++ b/src/sh_cat.c @@ -71,7 +71,8 @@ cat_entry msg_cat[] = { { MSG_CHECK_1, SH_ERR_STAMP, STAMP, N_("msg=\"File check completed.\" time=\"%ld\" kBps=\"%f\"")}, { MSG_CHECK_2, SH_ERR_STAMP, STAMP, N_("msg=\"File check starting.\"")}, { MSG_STAMP, SH_ERR_STAMP, STAMP, N_("msg=\"---- TIMESTAMP ----\"")}, - + { MSG_DCLOSE, SH_ERR_NOTICE, RUN, N_("msg=\"Finished writing baseline database.\"")}, + { MSG_D_START, SH_ERR_INFO, RUN, N_("msg=\"Downloading configuration file\"")}, { MSG_D_DSTART, SH_ERR_INFO, RUN, N_("msg=\"Downloading database file\"")}, { MSG_D_FAIL, SH_ERR_INFO, RUN, N_("msg=\"No file from server, trying local file\"")}, @@ -223,6 +224,7 @@ cat_entry msg_cat[] = { { MSG_TCP_EBGN, SH_ERR_ERR, TCP, N_("msg=\"Error in big integer library\"")}, { MSG_TCP_CREG, SH_ERR_ALL, TCP, N_("msg=\"Registered %s, salt %s, verifier %s\"")}, + { MSG_TCP_AREG, SH_ERR_ALL, TCP, N_("msg=\"Registered %s, hostname %s\"")}, { MSG_TCP_FAUTH, SH_ERR_INFO, TCP, N_("msg=\"Force authentication\" host=\"%s\"")}, { MSG_TCP_RESCLT, SH_ERR_SEVERE, TCP, N_("msg=\"Cannot resolve client name\" host=\"%s\"")}, @@ -402,6 +404,7 @@ cat_entry msg_cat[] = { { MSG_CHECK_1, SH_ERR_STAMP, STAMP, N_("msg=<File check completed.>, time=<%ld>, kBps=<%f>")}, { MSG_CHECK_2, SH_ERR_STAMP, STAMP, N_("msg=<File check starting.>")}, { MSG_STAMP, SH_ERR_STAMP, STAMP, N_("msg=<---- TIMESTAMP ---->")}, + { MSG_DCLOSE, SH_ERR_NOTICE, RUN, N_("msg=<Finished writing baseline database.>")}, { MSG_D_START, SH_ERR_INFO, RUN, N_("msg=<Downloading configuration file>")}, { MSG_D_DSTART, SH_ERR_INFO, RUN, N_("msg=<Downloading database file>")}, @@ -566,6 +569,7 @@ cat_entry msg_cat[] = { { MSG_TCP_EBGN, SH_ERR_ERR, TCP, N_("msg=<Error in big integer library>")}, { MSG_TCP_CREG, SH_ERR_ALL, TCP, N_("msg=<Registered %s, salt %s, verifier %s>")}, + { MSG_TCP_AREG, SH_ERR_ALL, TCP, N_("msg=<Registered %s, hostname %s>")}, { MSG_TCP_FAUTH, SH_ERR_INFO, TCP, N_("msg=<Force authentication>, client=<%s>")}, { MSG_TCP_RESCLT, SH_ERR_SEVERE, TCP, N_("msg=<Cannot resolve client name> host=<%s>")}, diff --git a/src/sh_checksum.c b/src/sh_checksum.c index 0587edc..e434d5c 100644 --- a/src/sh_checksum.c +++ b/src/sh_checksum.c @@ -407,7 +407,7 @@ void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { usedspace = freespace = 0; } -void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) +void SHA256_Final(sha2_byte digest[SHA256_DIGEST_LENGTH], SHA256_CTX* context) { sha2_word32 *d = (sha2_word32*)digest; unsigned int usedspace; @@ -481,7 +481,7 @@ void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) #include "sh_utils.h" /* If buffer is of length KEYBUF_SIZE, the digest will fit */ -char *SHA256_End(SHA256_CTX* context, char buffer[]) +char *SHA256_End(SHA256_CTX* context, char buffer[KEYBUF_SIZE]) { sha2_byte digest[SHA256_DIGEST_LENGTH]; diff --git a/src/sh_database.c b/src/sh_database.c index fdeed45..31a5919 100644 --- a/src/sh_database.c +++ b/src/sh_database.c @@ -283,7 +283,7 @@ static int insert_value (char * ptr, const char * str) static void init_db_entry (dbins * ptr) { - memset (ptr, (int) '\0', sizeof(dbins)); + memset (ptr, 0, sizeof(dbins)); ptr->next = NULL; return; } @@ -1122,12 +1122,7 @@ int sh_database_query (char * query, /*@out@*/ long * id) * We don't check the return value because it's useless (failure due * to lack of access permission is not reported). */ -#if !defined(__x86_64__) - /* - * libmysql segfaults on x86-64 if this is used - */ mysql_options(db_conn, MYSQL_READ_DEFAULT_GROUP, _("samhain")); -#endif status = 0; @@ -1148,6 +1143,7 @@ int sh_database_query (char * query, /*@out@*/ long * id) SL_RETURN(0, _("sh_database_query")); } } + connection_status = S_TRUE; } else @@ -1410,7 +1406,7 @@ long sh_database_entry (dbins * db_entry, long id) } /*@-type@*//* byte* versus char[..] */ if (attr_tab[i].inHash == 1 && - ((char *)(db_entry)+attr_tab[i].off) != '\0') + *((char *)(db_entry)+attr_tab[i].off) != '\0') { (void)md5Update(&crc, (sh_byte*) ((char *)(db_entry)+attr_tab[i].off), diff --git a/src/sh_dbIO.c b/src/sh_dbIO.c index 0ac9194..1f9b152 100644 --- a/src/sh_dbIO.c +++ b/src/sh_dbIO.c @@ -30,7 +30,7 @@ #include "sh_dbIO_int.h" #include "sh_hash.h" #include "sh_dbIO.h" -#include "sh_gpg.h" +#include "sh_sig.h" #include "sh_tiger.h" #include "sh_xfer.h" #include "sh_pthread.h" @@ -151,6 +151,8 @@ static int sh_dbIO_setdataent (SL_TICKET fd, char * line, int size, SL_RETURN( retval, _("sh_dbIO_setdataent")); } +/* Seek to [SOF] and truncate remainder of file + */ static int sh_dbIO_setdataent_old (SL_TICKET fd, char * line, int size, const char * file) { @@ -224,12 +226,10 @@ static unsigned short * swap_short (unsigned short * iptr) else { /* alignment problem */ - unsigned char swap; - static unsigned short ooop; - unsigned char * ii; - ooop = *iptr; - ii = (unsigned char *) &ooop; - swap = ii[0]; ii[0] = ii[1]; ii[1] = swap; + static unsigned short ooop = *iptr; + unsigned short hi = (ooop & 0xff00); + unsigned short lo = (ooop & 0xff); + ooop = (lo << 8) | (hi >> 8); return &ooop; } return iptr; @@ -378,10 +378,87 @@ static char * unquote_path(char * line, long i) (void) sl_strlcpy (path, tmp, len); if (tmp) SH_FREE(tmp); + /* do not strip newline twice... if (len > 1) { if (path[len-2] == '\n') path[len-2] = '\0'; } + ****/ + return path; +} + +/****************************************************************** + * + * Use different init rootfs (patch by Kemal H.) + * + ******************************************************************/ + +static char * sh_dbIO_rootfs = NULL; +static size_t sh_dbIO_rootfs_len = 0; + +int sh_dbIO_init_rootfs (const char * rootfs) +{ + if (NULL == sh_dbIO_rootfs) + { + sh_dbIO_rootfs = sh_util_strdup (rootfs); + sh_dbIO_rootfs_len = sl_strlen(sh_dbIO_rootfs); + return 0; + } + return -1; +} + +size_t sh_dbIO_get_rootfs_len() +{ + return sh_dbIO_rootfs_len; +} + +/* Prepend rootfs when reading from config file ('path' must be allocated with sufficient space). + */ +char * sh_dbIO_rootfs_prepend(char * path) +{ + if (0 == sh_dbIO_rootfs_len) + return path; + + memmove (path + sh_dbIO_rootfs_len, path, sl_strlen(path) + 1); + memcpy (path, sh_dbIO_rootfs, sh_dbIO_rootfs_len); + + return path; +} + + +/* Strip rootfs when writing to database file. + */ +char * sh_dbIO_rootfs_strip(char * path) +{ + if (sh_dbIO_rootfs_len == 0) + { + return path; + } + else + { + size_t len = sl_strlen(path); + + memmove (path, path + sh_dbIO_rootfs_len, len + 1 - sh_dbIO_rootfs_len); + if(path[0] != '/') + { + path[0]='/'; + path[1]='\0'; + } + } + + return path; +} + +char * sh_dbIO_rootfs_strip_link(char * path) +{ + if (sh_dbIO_rootfs_len == 0) + return path; + if (strstr(path, sh_dbIO_rootfs) == path) + { + size_t len = sl_strlen(path); + + memmove (path, path + sh_dbIO_rootfs_len, len + 1 - sh_dbIO_rootfs_len); + } return path; } @@ -406,7 +483,7 @@ static void corrupt_record(char * file, int line, const char * filepath) static void wrong_version(char * file, int line, const char * filepath) { dlog(1, file, line, - _("There is a record with a bad version number in the file signature database: %s\n"), + _("There is a record with a bad version number in the file signature database: %s\nThis may be caused by using '-t init' repeatedly to initialise the database, without (re)moving the database file.\n"), (NULL == filepath) ? _("(null)") : filepath); sh_error_handle((-1), file, line, 0, MSG_E_SUBGPATH, _("Record with bad version number in file signature database"), @@ -457,7 +534,7 @@ static size_t dbIO_fread_struct (sh_filestore_t * ptr, FILE *stream, if (1 == 0) hexdump((unsigned char *)&old_struct, sizeof(old_struct)); - memset(&try_struct, '\0', sizeof(try_struct)); + memset(&try_struct, 0, sizeof(try_struct)); if (!memcmp(&old_struct, &try_struct, sizeof(try_struct))) return 0; /* NULL read */ if (1 != fread (try, sizeof(try), 1, stream)) @@ -580,7 +657,7 @@ static sh_file_t * sh_dbIO_getdataent (char * line, int size, } fullpath = unquote_path(line, i); - + /* Read next record -- Part Three -- Linkpath */ i = sh_dbIO_getline (sh_fin_fd, line, size); @@ -774,12 +851,12 @@ static SL_TICKET load_data_from_disk(const char * filepath) static SL_TICKET verify_data (SL_TICKET fd) { -#if defined(WITH_GPG) || defined(WITH_PGP) +#if defined(WITH_SIG) SL_TICKET fdTmp; /* extract the data and copy to temporary file */ - fdTmp = sh_gpg_extract_signed(fd); + fdTmp = sh_sig_extract_signed(fd); if (sig_termfast == 1) /* SIGTERM */ { @@ -793,12 +870,16 @@ static SL_TICKET verify_data (SL_TICKET fd) /* Validate signature of open file. */ - if (0 != sh_gpg_check_sign (fd, SIG_DATA)) + if (0 != sh_sig_check_signature (fd, SIG_DATA)) { sl_close(fd); return -1; } sl_rewind (fd); + + fdTmp = sh_sig_extract_signed_data(fd); + sl_close(fd); + fd = fdTmp; #endif return fd; @@ -1116,15 +1197,19 @@ static void seek_writeout_data(SL_TICKET fd, const char * path) return; } +/* Seek to [SOF] and truncate remainder + */ static int seek_writeout_data_old(SL_TICKET fd, const char * path) { char * line = SH_ALLOC(MAX_PATH_STORE+1); + /* This will do an ftruncate() after the sof marker + */ if (SL_ISERROR(sh_dbIO_setdataent_old (fd, line, MAX_PATH_STORE, path))) { SH_FREE(line); sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGPATH, - _("Failed to seek to end of baseline database"), + _("Failed to seek to start of baseline database"), _("seek_writeout_data_old"), path); aud_exit(FIL__, __LINE__, EXIT_FAILURE); @@ -1329,6 +1414,7 @@ static void write_record(SL_TICKET fd, sh_filestore_t * p, if (!linkpath || 0 == sl_strlen(linkpath)) lpath = ll; else + /* cppcheck-suppress uninitvar */ lpath = linkpath; if (pushdata_stdout == S_FALSE) @@ -1413,6 +1499,7 @@ static void sh_dbIO_data_write_int (file_type * buf, char * fileHash, else { pushdata_fd = open_writeout_data(outpath); + /* Seek to eof */ seek_writeout_data(pushdata_fd, outpath); } } @@ -1423,13 +1510,13 @@ static void sh_dbIO_data_write_int (file_type * buf, char * fileHash, { TPT((0, FIL__, __LINE__, _("msg=<Update.>\n"))); pushdata_fd = open_writeout_data(outpath); + /* Seek to sof and truncate */ seek_writeout_data_old(pushdata_fd, outpath); } } - - if (!buf) { - memset(&p, '\0', sizeof(sh_filestore_t)); - } + + /* unconditionally initialize the structure */ + memset(&p, 0, sizeof(sh_filestore_t)); if (buf != NULL) { @@ -1478,7 +1565,19 @@ static void sh_dbIO_data_write_int (file_type * buf, char * fileHash, { if (sh.flag.checkSum != SH_CHECK_INIT || (buf == NULL && fileHash == NULL)) { - sl_close (pushdata_fd); + if (SL_ISERROR(sl_close (pushdata_fd))) + { + char * tmp = sh_util_safe_name(outpath); + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGPATH, + _("Failed to close baseline database"), + _("sh_dbIO_data_write_int"), + tmp); + SH_FREE(tmp); + } + else { + if (sh.flag.checkSum == SH_CHECK_INIT) + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_DCLOSE); + } pushdata_fd = -1; } } diff --git a/src/sh_entropy.c b/src/sh_entropy.c index bf2a3ee..c55dad6 100644 --- a/src/sh_entropy.c +++ b/src/sh_entropy.c @@ -333,7 +333,7 @@ int sh_entropy(int nbytes, char * nbuf) if (nbytes > KEY_BYT) nbytes = KEY_BYT; - memset(nbuf, '\0', nbytes); + memset(nbuf, 0, nbytes); #ifdef NAME_OF_DEV_URANDOM m_count = read_mbytes ( 10, NAME_OF_DEV_URANDOM, nbuf, nbytes); @@ -369,7 +369,7 @@ int sh_entropy(int nbytes, char * nbuf) { /* -- Add previous entropy into the new pool. -- */ - memset(addbuf, '\0', sizeof(addbuf)); + memset(addbuf, 0, sizeof(addbuf)); for (i = 0; i < m_count; ++i) addbuf[i] = nbuf[i]; for (i = 0; i < KEY_BYT; ++i) @@ -377,7 +377,7 @@ int sh_entropy(int nbytes, char * nbuf) keybuf = (char *) sh_tiger_hash_uint32 (addbuf, TIGER_DATA, 2 * KEY_BYT, kbuf, KEY_BYT/sizeof(UINT32)); - memset(addbuf, '\0', sizeof(addbuf)); + memset(addbuf, 0, sizeof(addbuf)); /* -- Give out nbytes bytes from the new pool. -- */ @@ -389,8 +389,8 @@ int sh_entropy(int nbytes, char * nbuf) nbuf[i] = keybuf[i]; } SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); - memset (keybuf, '\0', KEY_BYT); - memset (kbuf, '\0', sizeof(kbuf)); + memset (keybuf, 0, KEY_BYT); + memset (kbuf, 0, sizeof(kbuf)); SL_RETURN(0, _("sh_entropy")); } @@ -415,7 +415,7 @@ int sh_entropy(int nbytes, char * nbuf) #define FD_SETSIZE 32 #endif #ifndef FD_ZERO -#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p))) +#define FD_ZERO(p) memset((char *)(p), 0, sizeof(*(p))) #endif #include "sh_static.h" @@ -952,7 +952,7 @@ int sh_entropy(int nbytes, char * nbuf) keybuf = (char *) sh_tiger_hash_uint32 ((char *) tseed, TIGER_DATA, sizeof(tseed), kbuf, KEY_BYT/sizeof(UINT32)); - memset(addbuf, '\0', sizeof(addbuf)); + memset(addbuf, 0, sizeof(addbuf)); for (i = 0; i < KEY_BYT; ++i) { addbuf[i] = keybuf[i]; @@ -973,7 +973,7 @@ int sh_entropy(int nbytes, char * nbuf) /* add previous entropy into the new pool */ - memset(addbuf, '\0', sizeof(addbuf)); + memset(addbuf, 0, sizeof(addbuf)); for (i = 0; i < KEY_BYT; ++i) { addbuf[i] = keybuf[i]; @@ -982,7 +982,7 @@ int sh_entropy(int nbytes, char * nbuf) keybuf = (char *) sh_tiger_hash_uint32 (addbuf, TIGER_DATA, sizeof(addbuf), kbuf, KEY_BYT/sizeof(UINT32)); - memset(addbuf, '\0', sizeof(addbuf)); + memset(addbuf, 0, sizeof(addbuf)); /* store in system pool */ @@ -991,8 +991,8 @@ int sh_entropy(int nbytes, char * nbuf) skey->poolv[i] = keybuf[i]; skey->poolc = KEY_BYT; SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); - memset (buffer, '\0', BUF_ENT+2); - memset (keybuf, '\0', KEY_BYT); + memset (buffer, 0, BUF_ENT+2); + memset (keybuf, 0, KEY_BYT); SH_FREE(buffer); } else @@ -1029,13 +1029,13 @@ void Test_entropy (CuTest *tc) for (count = 0; count < 20; ++count) { - memset(skey->poolv, '\0', KEY_BYT); + memset(skey->poolv, 0, KEY_BYT); skey->poolc = 0; status = sh_entropy (24, bufx); CuAssertTrue(tc, 0 == status); - memset(skey->poolv, '\0', KEY_BYT); + memset(skey->poolv, 0, KEY_BYT); skey->poolc = 0; status = sh_entropy (24, bufy); diff --git a/src/sh_err_console.c b/src/sh_err_console.c index c3a8269..c813039 100644 --- a/src/sh_err_console.c +++ b/src/sh_err_console.c @@ -32,8 +32,11 @@ #include <stdio.h> #include <sys/types.h> #include <fcntl.h> +#include <sys/stat.h> #include <unistd.h> #include <signal.h> +#include <sys/socket.h> +#include <sys/un.h> extern int OnlyStderr; @@ -140,7 +143,7 @@ static void remove_message() MSG_NOERROR|IPC_NOWAIT); } while (rc < 0 && errno == EINTR); - memset(&recv_msg, '\0', sizeof(recv_msg)); + memset(&recv_msg, 0, sizeof(recv_msg)); return; } @@ -189,7 +192,7 @@ static int push_message_queue (const char * msg) if (count > 1) { - memset(recv_msg, '\0', MY_MAX_MSG+1); + memset(recv_msg, 0, MY_MAX_MSG+1); SH_FREE(recv_msg); SL_RETURN(-1, _("push_message_queue")); } @@ -213,13 +216,13 @@ static int push_message_queue (const char * msg) } else { TPT(( 0, FIL__, __LINE__, _("msg=<msgsnd: %s> errno=<%d>\n"), sh_error_message(errno, errbuf, sizeof(errbuf)), errno)); - memset(recv_msg, '\0', MY_MAX_MSG+1); + memset(recv_msg, 0, MY_MAX_MSG+1); SH_FREE(recv_msg); SL_RETURN(-1, _("push_message_queue")); } } - memset(recv_msg, '\0', MY_MAX_MSG+1); + memset(recv_msg, 0, MY_MAX_MSG+1); SH_FREE(recv_msg); SL_RETURN(0, _("push_message_queue")); @@ -244,9 +247,19 @@ void close_ipc() { sh_sem_close(); return; } static int count_dev_console = 0; +typedef enum { SH_LOG_UNIX, SH_LOG_OTHER, SH_LOG_INDEF } sh_log_devtype; + +static sh_log_devtype dt[2] = { SH_LOG_INDEF, SH_LOG_INDEF }; +static int st[2] = { SOCK_DGRAM, SOCK_DGRAM }; + void reset_count_dev_console(void) { count_dev_console = 0; + dt[0] = SH_LOG_INDEF; + dt[1] = SH_LOG_INDEF; + st[0] = SOCK_DGRAM; + st[1] = SOCK_DGRAM; + return; } @@ -283,6 +296,88 @@ char * sh_log_console_name (void) #define STDERR_FILENO 2 #endif +static int find_socktype(const char * name) +{ +#ifdef SOCK_SEQPACKET + int socktypes[3] = { SOCK_DGRAM, SOCK_SEQPACKET, SOCK_STREAM }; + int try = 3; +#else + int socktypes[2] = { SOCK_DGRAM, SOCK_STREAM }; + int try = 2; +#endif + int i; + for (i = 0; i < try; ++i) { + struct sockaddr_un addr; + int fd; + + if ( (fd = socket(AF_UNIX, socktypes[i], 0)) == -1) { + return -1; + } + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + sl_strlcpy(addr.sun_path, name, sizeof(addr.sun_path)); + if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) { + close(fd); + return socktypes[i]; + } + close(fd); + } + return -1; +} + +int sh_log_console_open (const char * name, int slot) +{ + int fd = -1; + + if (dt[slot] == SH_LOG_INDEF) + { + struct stat sb; + if (retry_stat(FIL__, __LINE__, name, &sb) == 0) + { + if ((sb.st_mode & S_IFMT) == S_IFSOCK) + { + dt[slot] = SH_LOG_UNIX; + st[slot] = find_socktype(name); + if (st[slot] == -1) { + sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, + _("Could not determine socket type."), + name); + } + } + else + dt[slot] = SH_LOG_OTHER; + } + } + + if (dt[slot] == SH_LOG_OTHER) { + fd = open ( name, O_WRONLY|O_APPEND|O_NOCTTY|O_NONBLOCK); + } + else if (dt[slot] == SH_LOG_UNIX && st[slot] != -1) { + struct sockaddr_un addr; + + if ( (fd = socket(AF_UNIX, st[slot], 0)) == -1) { + char ebuf[SH_ERRBUF_SIZE]; + int errnum = errno; + sh_error_handle ((-1), FIL__, __LINE__, errnum, MSG_E_SUBGEN, + sh_error_message(errnum, ebuf, sizeof(ebuf)), + name); + return -1; + } + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + sl_strlcpy(addr.sun_path, name, sizeof(addr.sun_path)); + if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + char ebuf[SH_ERRBUF_SIZE]; + int errnum = errno; + sh_error_handle ((-1), FIL__, __LINE__, errnum, MSG_E_SUBGEN, + sh_error_message(errnum, ebuf, sizeof(ebuf)), + name); + return -1; + } + } + return fd; +} + /* ---- Print out a message. ---- */ int sh_log_console (const /*@null@*/char *errmsg) @@ -335,11 +430,11 @@ int sh_log_console (const /*@null@*/char *errmsg) */ if ( OnlyStderr == S_FALSE ) { - fd[0] = open ( sh.srvcons.name, O_WRONLY|O_APPEND|O_NOCTTY|O_NONBLOCK); + fd[0] = sh_log_console_open ( sh.srvcons.name, 0); if (sh.srvcons.alt[0] != '\0') { - fd[1] = open (sh.srvcons.alt, O_WRONLY|O_APPEND|O_NOCTTY|O_NONBLOCK); + fd[1] = sh_log_console_open (sh.srvcons.alt, 1); ccMax = 2; } @@ -360,9 +455,11 @@ int sh_log_console (const /*@null@*/char *errmsg) do { val_return = write(fd[cc], errmsg, strlen(errmsg)); } while (val_return < 0 && errno == EINTR); - do { - val_return = write(fd[cc], "\r\n", 2); - } while (val_return < 0 && errno == EINTR); + if (dt[cc] != SH_LOG_UNIX || st[cc] == SOCK_STREAM) { + do { + val_return = write(fd[cc], "\r\n", 2); + } while (val_return < 0 && errno == EINTR); + } (void) sl_close_fd(FIL__, __LINE__, fd[cc]); service_failure[cc] = 0; } diff --git a/src/sh_err_log.c b/src/sh_err_log.c index da6ed06..8fc93b9 100644 --- a/src/sh_err_log.c +++ b/src/sh_err_log.c @@ -742,9 +742,9 @@ int sh_log_file (/*@null@*/char *errmsg, /*@null@*/char * inet_peer) (void) sl_strlcpy(current->logfile, logfile, strlen(logfile) + 1); current->service_failure = 0; current->log_start = S_TRUE; - memset(current->sigkey_old, (int)'\0', KEY_LEN+1); - memset(current->sigkey_new, (int)'\0', KEY_LEN+1); - memset(current->crypto, (int)'\0', KEY_LEN+1); + memset(current->sigkey_old, 0, KEY_LEN+1); + memset(current->sigkey_new, 0, KEY_LEN+1); + memset(current->crypto, 0, KEY_LEN+1); current->next = logfile_list; logfile_list = current; } @@ -943,7 +943,7 @@ int sh_log_file (/*@null@*/char *errmsg, /*@null@*/char * inet_peer) errFlags.databaselevel = store7; - memset (crypto, (int) '\0', KEY_LEN); + memset (crypto, 0, KEY_LEN); sh.flag.log_start = S_FALSE; current->log_start = S_FALSE; } @@ -1045,8 +1045,8 @@ int sh_log_file (/*@null@*/char *errmsg, /*@null@*/char * inet_peer) /* --- Clean up and free record. --- */ - memset (log_msg.msg, (int)'\0', (size_t)(status + 2*KEY_LEN + 32)); - memset (log_msg.signature, (int)'\0', KEY_LEN); + memset (log_msg.msg, 0, (size_t)(status + 2*KEY_LEN + 32)); + memset (log_msg.signature, 0, KEY_LEN); (void) sh_unix_munlock (log_msg.msg, (size_t)(status + 2*KEY_LEN + 32)); SH_FREE(log_msg.msg); @@ -1283,7 +1283,7 @@ void sh_efile_report() status = sl_forward(fd); if (!SL_ISERROR(status)) - status = sl_write (fd, report, strlen(report)); + sl_write (fd, report, strlen(report)); (void) sl_sync(fd); /* make group writeable, such that nagios can truncate */ diff --git a/src/sh_error.c b/src/sh_error.c index 5ec934b..82ee3c8 100644 --- a/src/sh_error.c +++ b/src/sh_error.c @@ -243,6 +243,7 @@ void sh_error_dbg_switch(void) static int sh_error_set_classmask (const char * str, int * facility_mask) { char * p; + char * q; int num = 0; unsigned int i; size_t len; @@ -289,6 +290,8 @@ static int sh_error_set_classmask (const char * str, int * facility_mask) if (p == NULL) break; + q = p; while (*q != '\0') { *q = toupper( (int) *q); ++q; } + for (i = 0; i < SH_CLA_MAX; ++i) { if (i < SH_CLA_RAW_MAX) { @@ -494,15 +497,20 @@ int sh_error_convert_level (const char * str_s) { int i; int level = (-1); + char * tmp; + char * q; SL_ENTER(_("sh_error_convert_level")); if (str_s == NULL) SL_RETURN( -1, _("sh_error_convert_level")); + q = sh_util_strdup(str_s); + tmp = q; while (*tmp != '\0') { *tmp = tolower( (int) *tmp); ++tmp; } + for (i = 0; i < SH_EEF_MAX; ++i) { - if (0 == sl_strncmp(str_s, _(eef_tab[i].str), + if (0 == sl_strncmp(q, _(eef_tab[i].str), sl_strlen(eef_tab[i].str))) { level = eef_tab[i].val; @@ -510,6 +518,7 @@ int sh_error_convert_level (const char * str_s) } } + SH_FREE(q); SL_RETURN( level, _("sh_error_convert_level")); } @@ -553,10 +562,17 @@ int sh_error_set_level(const char * str_in, int * facility) register int i, j, f = BAD; int old_facility; - const char * str_s = str_in; + char * str_s; + char * str_orig; + char * tmp; SL_ENTER(_("sh_error_set_level")); + str_s = sh_util_strdup(str_in); + str_orig = str_s; + + tmp = str_s; while (*tmp != '\0') { *tmp = tolower( (int) *tmp); ++tmp; } + if (IsInitialized == BAD) (void) sh_error_init(); @@ -649,6 +665,7 @@ int sh_error_set_level(const char * str_in, int * facility) if (!str_s) { + if (str_orig) SH_FREE(str_orig); SL_RETURN ((-1), _("sh_error_set_level")); } /* skip to end of string @@ -674,10 +691,12 @@ int sh_error_set_level(const char * str_in, int * facility) *facility = old_facility; sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS, _("priority"), str_in); + SH_FREE(str_orig); SL_RETURN (-1, _("sh_error_set_level")); } compute_flag_err_debug(); compute_flag_err_info(); + SH_FREE(str_orig); SL_RETURN (0, _("sh_error_set_level")); } @@ -1422,7 +1441,7 @@ void sh_error_handle (int sev1, const char * file, long line, SH_FREE( lmsg->msg ); sh_replace_free(hexmsg); - memset ( lmsg, (int) '\0', sizeof(struct _log_t) ); + memset ( lmsg, 0, sizeof(struct _log_t) ); MUNLOCK( (char *) lmsg, sizeof(struct _log_t) ); SH_FREE( lmsg ); own_block = 0; diff --git a/src/sh_extern.c b/src/sh_extern.c index c048873..bc6fc47 100644 --- a/src/sh_extern.c +++ b/src/sh_extern.c @@ -992,6 +992,7 @@ char * sh_ext_popen_str (const char * command) sh_string_read(s, task.pipe, 0); if (sh_string_len(s) == 0) { + /* cppcheck-suppress syntaxError */ --try; retry_msleep(0, 100); } } while (sh_string_len(s) == 0 && try != 0); diff --git a/src/sh_fInotify.c b/src/sh_fInotify.c index 67162e7..8cdadf8 100644 --- a/src/sh_fInotify.c +++ b/src/sh_fInotify.c @@ -196,13 +196,13 @@ int sh_fInotify_run() /* Blocking read from inotify file descriptor. */ - len = sh_inotify_read_timeout(buffer, 16384, 1); + len = sh_inotify_read_timeout (buffer, 16384, 1); if (len > 0) { struct inotify_event *event; - int i = 0; - + long i = 0; + while (i < len) { event = (struct inotify_event *) &(buffer[i]); diff --git a/src/sh_files.c b/src/sh_files.c index c32c4bc..09fc559 100644 --- a/src/sh_files.c +++ b/src/sh_files.c @@ -19,7 +19,37 @@ #include "config_xor.h" -#if defined(HAVE_PTHREAD_MUTEX_RECURSIVE) +#if defined(HAVE_PTHREAD_MUTEX_RECURSIVE) && defined(HAVE_DIRENT_H) && defined(HAVE_SCANDIR) + +/* Linux */ +#if defined(__linux__) +#define _XOPEN_SOURCE 700 +#define SH_USE_SCANDIR 1 + +/* FreeBSD */ +#elif defined(__FreeBSD__) + +#if __FreeBSD__ >= 8 +#define __XSI_VISIBLE 700 +#define SH_USE_SCANDIR 1 +#endif + +/* OpenBSD */ +#elif defined(__OpenBSD__) +#define __POSIX_VISIBLE 200809 +#define SH_USE_SCANDIR 1 + +#elif defined(__NetBSD__) +#define _NETBSD_SOURCE +#define SH_USE_SCANDIR 1 + +/* other os */ +#else +#define _XOPEN_SOURCE 500 + +#endif + +#elif defined(HAVE_PTHREAD_MUTEX_RECURSIVE) #define _XOPEN_SOURCE 500 #endif @@ -35,7 +65,6 @@ */ #include <sys/types.h> #include <unistd.h> -#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -214,12 +243,18 @@ static char * sh_files_C_dequote (char * s, size_t * length) char * sh_files_parse_input(const char * str_s, size_t * len) { char * p; - + if (!str_s || *str_s == '\0') return NULL; *len = sl_strlen(str_s); - + if (sh.flag.checkSum == SH_CHECK_INIT) + { + size_t addspace = sh_dbIO_get_rootfs_len(); + if (addspace != 0 && S_TRUE == sl_ok_adds (*len, addspace)) + *len += addspace; + } + if ( (str_s[0] == '"' && str_s[*len-1] == '"' ) || (str_s[0] == '\'' && str_s[*len-1] == '\'') ) { @@ -621,7 +656,7 @@ static char * intern_find_morespecific_dir(zAVLTree * tree, size_t l_path = strlen(path); size_t l_name; char * candidate = NULL; - size_t l_candidate = 0; + volatile size_t l_candidate = 0; if (NULL == tree) return NULL; @@ -1420,6 +1455,9 @@ static int sh_files_pushfile (int class, const char * str_s) if (!p || len == 0) SL_RETURN((-1), _("sh_files_pushfile")); + if (sh.flag.checkSum == SH_CHECK_INIT) + p = sh_dbIO_rootfs_prepend(p); + if (len >= PATH_MAX) { /* Name too long @@ -1854,6 +1892,9 @@ static int sh_files_pushdir (int class, const char * str_s) SL_RETURN((-1), _("sh_files_pushdir")); } + if (sh.flag.checkSum == SH_CHECK_INIT) + tail = sh_dbIO_rootfs_prepend(tail); + len = sl_strlen(tail); if (len >= PATH_MAX) @@ -2045,8 +2086,16 @@ static int sh_files_hle_test (int offset, char * path) } #endif -static void * sh_dummy_dirlist; -static void * sh_dummy_tmpcat; +/* This is the LCG from Numerical Recipies. Deterministic. + */ +static unsigned int simple_rand(unsigned int * state) +{ + *state = 1664525 * (*state) + 1013904223; + return *state; +} + +void * sh_dummy_dirlist; +void * sh_dummy_tmpcat; /* -- Check a single directory and its content. Does not * check the directory inode itself. @@ -2060,6 +2109,10 @@ int sh_files_checkdir (int iclass, unsigned long check_flags, DIR * thisDir = NULL; struct dirent * thisEntry; +#if defined(SH_USE_SCANDIR) + struct dirent **entryList; + int entry; +#endif int status; int dummy = S_FALSE; dir_type * theDir; @@ -2246,25 +2299,46 @@ int sh_files_checkdir (int iclass, unsigned long check_flags, dirlist = NULL; dirlist_orig = NULL; +#if defined(SH_USE_SCANDIR) + entry = scandir(iname, &entryList, 0, alphasort); + while(entry > 0) { /* scandir() may return -1 on error! */ + entry--; + thisEntry = entryList[entry]; +#else do { thisEntry = readdir (thisDir); +#endif if (thisEntry != NULL) { ++theDir->NumAll; if (sl_strcmp (thisEntry->d_name, ".") == 0) { ++theDir->NumDirs; +#if defined(SH_USE_SCANDIR) + free(entryList[entry]); /* scandir() mallocs entries */ +#endif continue; } if (sl_strcmp (thisEntry->d_name, "..") == 0) { ++theDir->NumDirs; +#if defined(SH_USE_SCANDIR) + free(entryList[entry]); /* scandir() mallocs entries */ +#endif continue; } dirlist = addto_sh_dirlist (thisEntry, dirlist); +#if defined(SH_USE_SCANDIR) + free(entryList[entry]); /* scandir() mallocs entries */ +#endif } - } while (thisEntry != NULL); - + } +#if defined(SH_USE_SCANDIR) + free(entryList); +#else + while (thisEntry != NULL); +#endif + SH_MUTEX_UNLOCK(mutex_readdir); closedir (thisDir); @@ -2289,11 +2363,7 @@ int sh_files_checkdir (int iclass, unsigned long check_flags, BREAKEXIT(sh_derr); -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_RAND_R) - if (0 == (rand_r(&state) % 5)) (void) sh_derr(); -#else - if (0 == state * (rand() % 5)) (void) sh_derr(); -#endif + if (0 == (simple_rand(&state) % 5)) (void) sh_derr(); /* ---- Check the file. ---- */ @@ -2636,11 +2706,7 @@ ShFileType sh_files_filecheck (int class, unsigned long check_flags, BREAKEXIT(sh_derr); -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_RAND_R) - if (0 == (rand_r(&state) % 2)) (void) sh_derr(); -#else - if (0 == state * (rand() % 2)) (void) sh_derr(); -#endif + if (0 == (simple_rand(&state) % 2)) (void) sh_derr(); if (dirName && infileName && (dirName[0] == '/') && (dirName[1] == '\0') && (infileName[0] == '/') && (infileName[1] == '\0')) @@ -2762,6 +2828,10 @@ ShFileType sh_files_filecheck (int class, unsigned long check_flags, if (S_TRUE == sh_ignore_chk_mod(theFile->fullpath)) MODI_SET(theFile->check_flags, MODI_NOCHECK); sh_tiger_get_mask_hashtype(&(theFile->check_flags)); + + sh_dbIO_rootfs_strip(theFile->fullpath); + if (theFile->link_path) + sh_dbIO_rootfs_strip_link(theFile->link_path); sh_dbIO_data_write (theFile, fileHash); } else if (sh.flag.checkSum == SH_CHECK_CHECK diff --git a/src/sh_filetype.c b/src/sh_filetype.c index 9abac46..3993d0b 100644 --- a/src/sh_filetype.c +++ b/src/sh_filetype.c @@ -596,6 +596,8 @@ int main (int argc, char * argv[]) fprintf(stdout, "%s: %s\n", argv[1], filetype); + fclose(fh); + return 0; } return 1; diff --git a/src/sh_filter.c b/src/sh_filter.c index 4cd9578..aa9c471 100644 --- a/src/sh_filter.c +++ b/src/sh_filter.c @@ -114,6 +114,7 @@ int sh_filter_add (const char * str, sh_filter_type * filter, int type) SL_RETURN((-1), _("sh_filter_filteradd")); } + /* cppcheck-suppress uninitvar */ i = *ntok; if (i == SH_FILT_NUM) { SL_RETURN((-1), _("sh_filter_filteradd")); @@ -292,7 +293,7 @@ sh_filter_type * sh_filter_alloc(void) { sh_filter_type * filter = SH_ALLOC(sizeof(sh_filter_type)); - memset(filter, '\0', sizeof(sh_filter_type)); + memset(filter, 0, sizeof(sh_filter_type)); filter->for_c = 0; filter->fand_c = 0; filter->fnot_c = 0; diff --git a/src/sh_getopt.c b/src/sh_getopt.c index 7969d4e..8480614 100644 --- a/src/sh_getopt.c +++ b/src/sh_getopt.c @@ -290,6 +290,11 @@ static opttable_t op_table[] = { N_("Create database from file list"), HAS_ARG_YES, sh_dbCreate}, + { N_("init-rootfs"), + '-', + N_("Build database based on another rootfs"), + HAS_ARG_YES, + sh_dbIO_init_rootfs}, { N_("wait-on-check"), 'w', N_("Timed wait for end of filecheck (0 for no timeout)"), @@ -417,8 +422,8 @@ static void sh_getopt_print_log_facilities (void) #endif #ifdef HAVE_LIBPRELUDE - if (num > 0) fputc ('\n', stdout); ++num; - fputs (_(" prelude (0.9.6+)"), stdout); + if (num > 0) fputc ('\n', stdout); + fputs (_(" prelude (0.9.6+)"), stdout); ++num; #endif if (num == 0) @@ -475,10 +480,10 @@ static void sh_getopt_print_options (void) #ifdef WITH_GPG if (num > 0) fputc ('\n', stdout); - printf (_(" GnuPG signatures (%s)"), DEFAULT_GPG_PATH); ++num; -#ifdef HAVE_GPG_CHECKSUM + printf (_(" GnuPG signatures (%s)"), DEFAULT_SIG_PATH); ++num; +#ifdef HAVE_SIG_CHECKSUM if (num > 0) fputc ('\n', stdout); - printf (_(" -- GnuPG checksum: %s"), GPG_HASH); ++num; + printf (_(" -- GnuPG checksum: %s"), SIG_HASH); ++num; #endif #ifdef USE_FINGERPRINT if (num > 0) fputc ('\n', stdout); @@ -634,7 +639,7 @@ static int sh_getopt_version (const char * dummy) static int sh_getopt_copyright (const char * dummy) { fprintf (stdout, "%s", - _("Copyright (C) 1999-2008 Rainer Wichmann"\ + _("Copyright (C) 1999-2019 Rainer Wichmann"\ " (http://la-samhna.de).\n\n")); fprintf (stdout, "%s", diff --git a/src/sh_gpg.c b/src/sh_gpg.c deleted file mode 100644 index e06d42c..0000000 --- a/src/sh_gpg.c +++ /dev/null @@ -1,1035 +0,0 @@ -/* SAMHAIN file system integrity testing */ -/* Copyright (C) 1999, 2000 Rainer Wichmann */ -/* */ -/* This program is free software; you can redistribute it */ -/* and/or modify */ -/* it under the terms of the GNU General Public License as */ -/* published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include "config_xor.h" - -#include <stdio.h> -#include <stdlib.h> - - -#if defined(WITH_GPG) || defined(WITH_PGP) - -#include <unistd.h> -#include <fcntl.h> -#include <signal.h> -#if defined(SH_WITH_SERVER) -#include <pwd.h> -#endif -#include <sys/stat.h> -#include <sys/types.h> -#include <errno.h> -#include <sys/wait.h> - -#include <string.h> -#ifdef HAVE_MEMORY_H -#include <memory.h> -#endif - - -#if !defined(O_NONBLOCK) -#if defined(O_NDELAY) -#define O_NONBLOCK O_NDELAY -#else -#define O_NONBLOCK 0 -#endif -#endif - - -#include "samhain.h" -#include "sh_utils.h" -#include "sh_error.h" -#include "sh_tiger.h" -#if defined(SH_WITH_SERVER) -#define SH_NEED_PWD_GRP 1 -#include "sh_static.h" -#endif -#include "sh_gpg.h" - -static struct { - char conf_id[SH_MINIBUF+1]; - char conf_fp[SH_MINIBUF+1]; - char data_id[SH_MINIBUF+1]; - char data_fp[SH_MINIBUF+1]; -} gp; - -typedef struct { - pid_t pid; - FILE * pipe; -} sh_gpg_popen_t; - -#define SH_GPG_OK 0 -#define SH_GPG_BAD 1 -#define SH_GPG_BADSIGN 2 - -/* replace #if 0 by #if 1 and set an appropriate path in front of '/pdbg.' - * for debugging - */ -#if 0 -#define PDGBFILE "/pdbg." -#endif - -#if defined(PDGBFILE) -FILE * pdbg; -FILE * pdbgc; -#define PDBG_OPEN pdbg = fopen(PDGBFILE"main", "a") -#define PDBG_CLOSE sl_fclose (FIL__, __LINE__, pdbg) -#define PDBG(arg) fprintf(pdbg, "PDBG: step %d\n", arg); fflush(pdbg) -#define PDBG_D(arg) fprintf(pdbg, "PDBG: %d\n", arg); fflush(pdbg) -#define PDBG_S(arg) fprintf(pdbg, "PDBG: %s\n", arg); fflush(pdbg) - -#define PDBGC_OPEN pdbgc = fopen(PDGBFILE"child", "a") -#define PDBGC_CLOSE sl_fclose (FIL__, __LINE__, pdbgc) -#define PDBGC(arg) fprintf(pdbgc, "PDBG: step %d\n", arg); fflush(pdbgc) -#define PDBGC_D(arg) fprintf(pdbgc, "PDBG: %d\n", arg); fflush(pdbgc) -#define PDBGC_S(arg) fprintf(pdbgc, "PDBG: %s\n", arg); fflush(pdbgc) -#else -#define PDBG_OPEN -#define PDBG_CLOSE -#define PDBG(arg) -#define PDBG_D(arg) -#define PDBG_S(arg) -#define PDBGC_OPEN -#define PDBGC_CLOSE -#define PDBGC(arg) -#define PDBGC_D(arg) -#define PDBGC_S(arg) -#endif - -#undef FIL__ -#define FIL__ _("sh_gpg.c") - -#ifdef GPG_HASH - -static int sh_gpg_checksum (SL_TICKET checkfd, int flag) -{ - char * test_gpg; - char * test_ptr1 = NULL; - char * test_ptr2 = NULL; - char wstrip1[128]; - char wstrip2[128]; - int i, k; -#include "sh_gpg_chksum.h" - - SL_ENTER(_("sh_gpg_checksum")); - - test_gpg = sh_tiger_hash_gpg (DEFAULT_GPG_PATH, checkfd, TIGER_NOLIM); - - test_ptr1 = strchr(GPG_HASH, ':'); - if (test_gpg != NULL) - test_ptr2 = strchr(test_gpg, ':'); - - if (test_ptr2 != NULL) - test_ptr2 += 2; - else - test_ptr2 = test_gpg; - if (test_ptr1 != NULL) - test_ptr1 += 2; - else - test_ptr1 = GPG_HASH; - - /* Tue Jun 24 23:11:54 CEST 2003 (1.7.9) -- strip whitespace - */ - k = 0; - for (i = 0; i < 127; ++i) - { - if (test_ptr1[i] == '\0') - break; - if (test_ptr1[i] != ' ') - { - wstrip1[k] = test_ptr1[i]; - ++k; - } - } - wstrip1[k] = '\0'; - - for(i = 0; i < KEY_LEN; ++i) - { - if (gpgchk[i] != wstrip1[i]) - { - sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0, MSG_E_GPG_CHK, - gpgchk, wstrip1); - break; - } - } - - k = 0; - if (test_ptr2) - { - for (i = 0; i < 127; ++i) - { - if (test_ptr2[i] == '\0') - break; - if (test_ptr2[i] != ' ') - { - wstrip2[k] = test_ptr2[i]; - ++k; - } - } - } - wstrip2[k] = '\0'; - - if (0 != sl_strncmp(wstrip1, wstrip2, 127)) - { - TPT(((0), FIL__, __LINE__, _("msg=<pgp checksum: %s>\n"), test_gpg)); - TPT(((0), FIL__, __LINE__, _("msg=<Compiled-in : %s>\n"), GPG_HASH)); - TPT(((0), FIL__, __LINE__, _("msg=<wstrip1 : %s>\n"), wstrip1)); - TPT(((0), FIL__, __LINE__, _("msg=<wstrip2 : %s>\n"), wstrip2)); - if (flag == 1) - sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_GPG, - GPG_HASH, test_gpg); - dlog(1, FIL__, __LINE__, _("The compiled-in checksum of the gpg binary\n(%s)\ndoes not match the actual checksum\n(%s).\nYou need to recompile with the correct checksum."), wstrip1, wstrip2); - SH_FREE(test_gpg); - SL_RETURN((-1), _("sh_gpg_checksum")); - } - SH_FREE(test_gpg); - SL_RETURN( (0), _("sh_gpg_checksum")); -} -#endif - -struct startup_info { - long line; - char * program; - long uid; - char * path; - char * key_uid; - char * key_id; -}; - -static struct startup_info startInfo = { 0, NULL, 0, NULL, NULL, NULL }; - -void sh_gpg_log_startup (void) -{ - if (startInfo.program != NULL) - { - sh_error_handle ((-1), FIL__, startInfo.line, 0, MSG_START_GH, - startInfo.program, startInfo.uid, - startInfo.path, - startInfo.key_uid, startInfo.key_id); - } - return; -} - -static void sh_gpg_fill_startup (long line, char * program, long uid, char * path, - char * key_uid, char * key_id) -{ - startInfo.line = line; - startInfo.program = sh_util_strdup(program); - startInfo.uid = uid; - startInfo.path = sh_util_strdup(path); - startInfo.key_uid = sh_util_strdup(key_uid); - startInfo.key_id = sh_util_strdup(key_id); - return; -} - -static FILE * sh_gpg_popen (sh_gpg_popen_t *source, int fd, - int mode, char * id, char * homedir) -{ - extern int flag_err_debug; - int pipedes[2]; - FILE * outf = NULL; - char * envp[2]; - size_t len; - char path[256]; - char cc1[32]; - char cc2[32]; - - char cc0[2] = "-"; - char cc3[32]; - char cc4[SH_PATHBUF+32]; - char cc5[32]; - - - char * arg[9]; - -#if defined(HAVE_GPG_CHECKSUM) - SL_TICKET checkfd = -1; - int myrand; - int i; -#if defined(__linux__) - int get_the_fd(SL_TICKET); - char pname[128]; - int pfd; - int val_return; -#endif -#endif - - SL_ENTER(_("sh_gpg_popen")); - - /* -- GnuPG -- */ - sl_strlcpy (path, DEFAULT_GPG_PATH, 256); - sl_strlcpy (cc1, _("--status-fd"), 32); - sl_strlcpy (cc2, _("--verify"), 32); - sl_strlcpy (cc3, _("--homedir"), 32); - /* sl_strlcpy (cc4, sh.effective.home, SH_PATHBUF+32); */ - sl_strlcpy (cc4, homedir, SH_PATHBUF+32); - sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32); - sl_strlcpy (cc5, _("--no-tty"), 32); - - /* fprintf(stderr, "YULE: homedir=%s\n", homedir); */ - -#if defined(SH_WITH_SERVER) - if (0 == sl_ret_euid()) /* privileges not dropped yet */ - { - struct stat lbuf; - int status_stat = 0; -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R) - struct passwd pwd; - char * buffer = SH_ALLOC(SH_PWBUF_SIZE); - struct passwd * tempres; - sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres); -#else - struct passwd * tempres = sh_getpwnam(DEFAULT_IDENT); -#endif - - if (!tempres) - { - dlog(1, FIL__, __LINE__, - _("User %s does not exist. Please add the user to your system.\n"), - DEFAULT_IDENT); - status_stat = -1; - } - if (!tempres->pw_dir || tempres->pw_dir[0] == '\0') - { - dlog(1, FIL__, __LINE__, - _("User %s does not have a home directory.\nPlease add the home directory for this user to your system.\n"), - DEFAULT_IDENT); - status_stat = -2; - } - if (status_stat == 0) - { - sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32); - sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32); - status_stat = retry_lstat(FIL__, __LINE__, cc4, &lbuf); - if (status_stat == -1) - { - dlog(1, FIL__, __LINE__, - _("Gnupg directory %s for user %s\ndoes not exist or is not accessible.\nPlease add the directory and put the keyring (pubring.gpg) there\nto verify the configuration file.\n"), - cc4, DEFAULT_IDENT); - status_stat = -3; - } - } - if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid) - { - dlog(1, FIL__, __LINE__, - _("Gnupg directory %s\nis not owned by user %s.\n"), - cc4, DEFAULT_IDENT); - status_stat = -4; - } - if (status_stat == 0) - { - sl_strlcat (cc4, _("/pubring.gpg"), SH_PATHBUF+32); - status_stat = retry_lstat(FIL__, __LINE__, cc4, &lbuf); - if (status_stat == -1) - { - dlog(1, FIL__, __LINE__, - _("Gnupg public keyring %s for user %s\ndoes not exist or is not accessible.\nPlease add the directory and put the keyring (pubring.gpg) there\nto verify the configuration file.\n"), - cc4, DEFAULT_IDENT); - status_stat = -5; - } - } - if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid) - { - dlog(1, FIL__, __LINE__, - _("Gnupg public keyring %s\nis not owned by user %s.\n"), - cc4, DEFAULT_IDENT); - status_stat = -6; - } - if (status_stat != 0) - { - sh_error_handle((-1), FIL__, __LINE__, status_stat, MSG_EXIT_ABORT1, - sh.prg_name); - aud_exit (FIL__, __LINE__, EXIT_FAILURE); - } - sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32); - sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32); -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R) - SH_FREE(buffer); -#endif - } -#endif - - arg[0] = path; - arg[1] = cc1; - arg[2] = "1"; - arg[3] = cc2; - arg[4] = cc3; - arg[5] = cc4; - arg[6] = cc5; - arg[7] = cc0; - arg[8] = NULL; - - /* catch 'unused parameter' compiler warning - */ - (void) mode; - (void) id; - - /* use homedir of effective user - */ - len = sl_strlen(sh.effective.home) + 6; - envp[0] = calloc(1, len); /* free() ok */ - if (envp[0] != NULL) - sl_snprintf (envp[0], len, _("HOME=%s"), sh.effective.home); - envp[1] = NULL; - - /* Create the pipe - */ - if (aud_pipe(FIL__, __LINE__, pipedes) < 0) - { - if (envp[0] != NULL) - free(envp[0]); - SL_RETURN( (NULL), _("sh_gpg_popen")); - } - - fflush (NULL); - - source->pid = aud_fork(FIL__, __LINE__); - - /* Failure - */ - if (source->pid == (pid_t) - 1) - { - sl_close_fd(FIL__, __LINE__, pipedes[0]); - sl_close_fd(FIL__, __LINE__, pipedes[1]); - if (envp[0] != NULL) - free(envp[0]); - SL_RETURN( (NULL), _("sh_gpg_popen")); - } - - if (source->pid == (pid_t) 0) - { - - /* child - make read side of the pipe stdout - */ - if (retry_aud_dup2(FIL__, __LINE__, - pipedes[STDOUT_FILENO], STDOUT_FILENO) < 0) - { - TPT(((0), FIL__, __LINE__, _("msg=<dup2 on pipe failed>\n"))); - dlog(1, FIL__, __LINE__, _("Internal error: dup2 failed\n")); - aud__exit(FIL__, __LINE__, EXIT_FAILURE); - } - - /* close the pipe descriptors - */ - sl_close_fd (FIL__, __LINE__, pipedes[STDIN_FILENO]); - sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]); - - if (retry_aud_dup2(FIL__, __LINE__, fd, STDIN_FILENO) < 0) - { - TPT(((0), FIL__, __LINE__, _("msg=<dup2 on fd failed>\n"))); - dlog(1, FIL__, __LINE__, _("Internal error: dup2 failed\n")); - aud__exit(FIL__, __LINE__, EXIT_FAILURE); - } - - /* don't leak file descriptors - */ - sh_unix_closeall (3, -1, S_TRUE); /* in child process */ - - if (flag_err_debug != S_TRUE) - { - if (NULL == freopen(_("/dev/null"), "r+", stderr)) - { - dlog(1, FIL__, __LINE__, _("Internal error: freopen failed\n")); - aud__exit(FIL__, __LINE__, EXIT_FAILURE); - } - } - - - /* We should become privileged if SUID, - * to be able to read the keyring. - * We have checked that gpg is OK, - * AND that only a trusted user could overwrite - * gpg. - */ - memset (skey, '\0', sizeof(sh_key_t)); - aud_setuid(FIL__, __LINE__, geteuid()); - - PDBGC_OPEN; - PDBGC_D((int)getuid()); - PDBGC_D((int)geteuid()); - - { - int i = 0; - while (arg[i] != NULL) - { - PDBGC_S(arg[i]); - ++i; - } - } - PDBGC_CLOSE; - - /* exec the program */ - -#if defined(__linux__) && defined(HAVE_GPG_CHECKSUM) - /* - * -- emulate an fexecve with checksum testing - */ - checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_GPG_PATH, SL_NOPRIV); - - if (0 != sh_gpg_checksum(checkfd, 0)) - { - sl_close(checkfd); - aud__exit(FIL__, __LINE__, EXIT_FAILURE); - } - - pfd = get_the_fd(checkfd); - do { - val_return = dup (pfd); - } while (val_return < 0 && errno == EINTR); - pfd = val_return; - sl_close(checkfd); - /* checkfd = -1; *//* never read */ - - sl_snprintf(pname, sizeof(pname), _("/proc/self/fd/%d"), pfd); - if (0 == access(pname, R_OK|X_OK)) /* flawfinder: ignore */ - - { - fcntl (pfd, F_SETFD, FD_CLOEXEC); - retry_aud_execve (FIL__, __LINE__, pname, arg, envp); - - dlog(1, FIL__, __LINE__, _("Unexpected error: execve %s failed\n"), - pname); - /* failed - */ - aud__exit(FIL__, __LINE__, EXIT_FAILURE); - } - - /* procfs not working, go ahead - */ -#endif - -#if defined(HAVE_GPG_CHECKSUM) - /* This is an incredibly ugly kludge to prevent an attacker - * from knowing when it is safe to slip in a fake executable - * between the integrity check and the execve - */ - myrand = (int) taus_get (); - - myrand = (myrand < 0) ? (-myrand) : myrand; - myrand = (myrand % 32) + 2; - - for (i = 0; i < myrand; ++i) - { - checkfd = sl_open_fastread(FIL__, __LINE__, - DEFAULT_GPG_PATH, SL_NOPRIV); - - if (0 != sh_gpg_checksum(checkfd, 0)) { - aud__exit(FIL__, __LINE__, EXIT_FAILURE); - } - sl_close(checkfd); - } -#endif - - retry_aud_execve (FIL__, __LINE__, DEFAULT_GPG_PATH, arg, envp); - dlog(1, FIL__, __LINE__, _("Unexpected error: execve %s failed\n"), - DEFAULT_GPG_PATH); - - /* failed - */ - TPT(((0), FIL__, __LINE__, _("msg=<execve failed>\n"))); - dlog(1, FIL__, __LINE__, _("Unexpected error: execve failed\n")); - aud__exit(FIL__, __LINE__, EXIT_FAILURE); - } - - /* parent - */ - - if (envp[0] != NULL) - free(envp[0]); - - sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]); - retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC); - retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFL, O_NONBLOCK); - - outf = fdopen (pipedes[STDIN_FILENO], "r"); - - if (outf == NULL) - { - aud_kill (FIL__, __LINE__, source->pid, SIGKILL); - sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]); - waitpid (source->pid, NULL, 0); - source->pid = 0; - SL_RETURN( (NULL), _("sh_gpg_popen")); - } - - SL_RETURN( (outf), _("sh_gpg_popen")); -} - - -static int sh_gpg_pclose (sh_gpg_popen_t *source) -{ - int status = 0; - - SL_ENTER(_("sh_gpg_pclose")); - - status = sl_fclose(FIL__, __LINE__, source->pipe); - if (status) - SL_RETURN( (-1), _("sh_gpg_pclose")); - - if (waitpid(source->pid, NULL, 0) != source->pid) - status = -1; - - source->pipe = NULL; - source->pid = 0; - SL_RETURN( (status), _("sh_gpg_pclose")); -} - -static -int sh_gpg_check_file_sign(int fd, char * sign_id, char * sign_fp, - char * homedir, int whichfile) -{ - struct stat buf; - char line[256]; - sh_gpg_popen_t source; - int have_id = BAD, have_fp = BAD, status = 0; - -#ifdef HAVE_GPG_CHECKSUM - SL_TICKET checkfd; -#endif - - SL_ENTER(_("sh_gpg_check_file_sign")); - - /* check whether GnuPG exists and has the correct checksum - */ - TPT(((0), FIL__, __LINE__, _("msg=<Check signature>\n"))); - TPT(((0), FIL__, __LINE__, _("msg=<gpg is %s>\n"), DEFAULT_GPG_PATH)); - - if (0 != retry_lstat(FIL__, __LINE__, DEFAULT_GPG_PATH, &buf)) - { - char errbuf[SH_ERRBUF_SIZE]; - - status = errno; - sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT, - sh_error_message(status, errbuf, sizeof(errbuf)), DEFAULT_GPG_PATH); - SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign")); - } - - if (0 != tf_trust_check (DEFAULT_GPG_PATH, SL_YESPRIV)) - SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign")); - -#ifdef HAVE_GPG_CHECKSUM - checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_GPG_PATH, SL_YESPRIV); - - if (0 != sh_gpg_checksum(checkfd, 1)) - { - sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, - _("Checksum mismatch"), - _("gpg_check_file_sign")); - sl_close(checkfd); - SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign")); - } - sl_close(checkfd); -#endif - - TPT(((0), FIL__, __LINE__, _("msg=<Open pipe to check signature>\n"))); - - fflush(NULL); - - source.pipe = sh_gpg_popen ( &source, fd, 0, NULL, homedir ); - - if (NULL == source.pipe) - { - sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, - _("Could not open pipe"), - _("gpg_check_file_sign")); - SL_RETURN( SH_GPG_BAD, _("sh_gpg_check_file_sign")); - } - - TPT(((0), FIL__, __LINE__, _("msg=<Open pipe success>\n"))); - - xagain: - - errno = 0; - - while (NULL != fgets(line, sizeof(line), source.pipe)) - { - - TPT(((0), FIL__, __LINE__, _("msg=<gpg out: %s>\n"), line)); - if (line[strlen(line)-1] == '\n') - line[strlen(line)-1] = ' '; - sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN, - line, - _("gpg_check_file_sign")); - - if (sl_strlen(line) < 18) - continue; - - /* Sun May 27 18:40:05 CEST 2001 - */ - if (0 == sl_strncmp(_("BADSIG"), &line[9], 6) || - 0 == sl_strncmp(_("ERRSIG"), &line[9], 6) || - 0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6) || - 0 == sl_strncmp(_("NODATA"), &line[9], 6) || - 0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6)) - { - if (0 == sl_strncmp(_("BADSIG"), &line[9], 6)) { - dlog(1, FIL__, __LINE__, - _("%s file is signed, but the signature is invalid."), - ((whichfile == 1) ? _("Configuration") : _("Database"))); - } - else if (0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6)) { - dlog(1, FIL__, __LINE__, - _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."), - ((whichfile == 1) ? _("Configuration") : _("Database")), - homedir); - } - else if (0 == sl_strncmp(_("ERRSIG"), &line[9], 6)) { - dlog(1, FIL__, __LINE__, - _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."), - ((whichfile == 1) ? _("Configuration") : _("Database")), - homedir); - } - else if (0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6)) { - dlog(1, FIL__, __LINE__, - _("%s file is signed, but the public key to verify the signature has expired."), - ((whichfile == 1) ? _("Configuration") : _("Database"))); - } - else if (0 == sl_strncmp(_("NODATA"), &line[9], 6)) { - dlog(1, FIL__, __LINE__, - _("%s file is not signed."), - ((whichfile == 1) ? _("Configuration") : _("Database"))); - } - - have_fp = BAD; have_id = BAD; - break; - } - if (0 == sl_strncmp(_("GOODSIG"), &line[9], 7)) - { - sl_strlcpy (sign_id, &line[25], SH_MINIBUF+1); - if (sign_id) - sign_id[sl_strlen(sign_id)-1] = '\0'; /* remove trailing '"' */ - have_id = GOOD; - } - if (0 == sl_strncmp(_("VALIDSIG"), &line[9], 8)) - { - strncpy (sign_fp, &line[18], 40); - sign_fp[40] = '\0'; - have_fp = GOOD; - } - } - - if (ferror(source.pipe) && errno == EAGAIN) - { - /* sleep 10 ms to avoid starving the gpg child writing to the pipe */ - retry_msleep(0,10); - clearerr(source.pipe); - goto xagain; - } - - sh_gpg_pclose (&source); - - TPT(((0), FIL__, __LINE__, _("msg=<Close pipe>\n"))); - - if (have_id == GOOD) - { - TPT(((0), FIL__, __LINE__, _("msg=<Got signator ID>\n"))); - } - if (have_fp == GOOD) - { - TPT(((0), FIL__, __LINE__, _("msg=<Got fingerprint>\n"))); - } - - if (have_id == GOOD && have_fp == GOOD) - SL_RETURN( SH_GPG_OK, _("sh_gpg_check_file_sign")); - else - { - if (have_id == BAD) - sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, - _("No good signature"), - _("gpg_check_file_sign")); - else - sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, - _("No fingerprint for key"), - _("gpg_check_file_sign")); - SL_RETURN( SH_GPG_BADSIGN, _("sh_gpg_check_file_sign")); - } -} - -int get_the_fd(SL_TICKET file_1); - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && \ - defined(HAVE_GETPWNAM_R) -#define USE_GETPWNAM_R 1 -#endif - -int sh_gpg_check_sign (long file, int what) -{ - int status = SH_GPG_BAD; - int fd = 0; - - static int smsg = S_FALSE; - char * tmp; - - char * sig_id; - char * sig_fp; - - char * homedir = sh.effective.home; -#if defined(SH_WITH_SERVER) - struct passwd * tempres; -#if defined(USE_GETPWNAM_R) - struct passwd pwd; - char * buffer = SH_ALLOC(SH_PWBUF_SIZE); -#endif -#endif - -#ifdef USE_FINGERPRINT -#include "sh_gpg_fp.h" -#endif - - SL_ENTER(_("sh_gpg_check_sign")); - - - if (what == SIG_CONF) - fd = get_the_fd(file); - if (what == SIG_DATA) - fd = get_the_fd(file); - - - if (fd < 0) - { - TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd)); - dlog(1, FIL__, __LINE__, - _("This looks like an unexpected internal error.\n")); -#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R) - SH_FREE(buffer); -#endif - SL_RETURN( (-1), _("sh_gpg_check_sign")); - } - -#if defined(SH_WITH_SERVER) -#if defined(USE_GETPWNAM_R) - sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres); -#else - tempres = sh_getpwnam(DEFAULT_IDENT); -#endif - if ((tempres != NULL) && (0 == sl_ret_euid())) - { - /* privileges not dropped yet*/ - homedir = tempres->pw_dir; - } -#endif - - if (what == SIG_CONF) - { - TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd)); - status = sh_gpg_check_file_sign(fd, gp.conf_id, gp.conf_fp, homedir, 1); - TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGUSR: |%s|>\n"), gp.conf_id)); - TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGFP: |%s|>\n"), gp.conf_fp)); - sig_id = gp.conf_id; sig_fp = gp.conf_fp; - } - - if (what == SIG_DATA) - { - TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd)); - status = sh_gpg_check_file_sign(fd, gp.data_id, gp.data_fp, homedir, 2); - TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGUSR: |%s|>\n"), gp.data_id)); - TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGFP: |%s|>\n"), gp.data_fp)); - sig_id = gp.data_id; sig_fp = gp.data_fp; - } - - if (SH_GPG_OK == status) - { -#ifdef USE_FINGERPRINT - if ((sl_strcmp(SH_GPG_FP, sig_fp) == 0)) - { - int i; - - for(i = 0; i < (int) sl_strlen(sig_fp); ++i) { - if (gpgfp[i] != sig_fp[i]) { - sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0, - MSG_E_GPG_FP, gpgfp, sig_fp); - break; } - } - - if (smsg == S_FALSE) { - tmp = sh_util_safe_name(sig_id); - sh_gpg_fill_startup (__LINE__, sh.prg_name, sh.real.uid, - (sh.flag.hidefile == S_TRUE) ? - _("(hidden)") : file_path('C', 'R'), - tmp, - sig_fp); - SH_FREE(tmp); } - smsg = S_TRUE; - -#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R) - SH_FREE(buffer); -#endif - SL_RETURN(0, _("sh_gpg_check_sign")); - } - else - { - /* fp mismatch */ - dlog(1, FIL__, __LINE__, - _("The fingerprint of the signing key: %s\ndoes not match the compiled-in fingerprint: %s.\nTherefore the signature could not be verified.\n"), - sig_fp, SH_GPG_FP); - sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, - _("Fingerprint mismatch"), _("gpg_check_sign")); - status = SH_GPG_BADSIGN; - } -#else /* ifdef USE_FINGERPRINT */ - if (smsg == S_FALSE) - { - tmp = sh_util_safe_name(sig_id); - sh_gpg_fill_startup (__LINE__, - sh.prg_name, sh.real.uid, - (sh.flag.hidefile == S_TRUE) ? - _("(hidden)") : file_path('C', 'R'), - tmp, sig_fp); - SH_FREE(tmp); - } - smsg = S_TRUE; - -#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R) - SH_FREE(buffer); -#endif - - SL_RETURN(0, _("sh_gpg_check_sign")); -#endif /* !ifdef USE_FINGERPRINT */ - } - - if (status != SH_GPG_OK) - { - uid_t e_uid = sl_ret_euid(); - char * e_home = sh.effective.home; - -#if defined(SH_WITH_SERVER) -#if defined(USE_GETPWNAM_R) - struct passwd e_pwd; - char * e_buffer = SH_ALLOC(SH_PWBUF_SIZE); - struct passwd * e_tempres; - sh_getpwnam_r(DEFAULT_IDENT, &e_pwd, e_buffer, SH_PWBUF_SIZE, &e_tempres); -#else - struct passwd * e_tempres = sh_getpwnam(DEFAULT_IDENT); -#endif - - if ((e_tempres != NULL) && (0 == sl_ret_euid())) - { - /* privileges not dropped yet */ - e_uid = e_tempres->pw_uid; - e_home = e_tempres->pw_dir; - } -#endif - dlog(1, FIL__, __LINE__, - _("The signature of the configuration file or the file signature database\ncould not be verified. Possible reasons are:\n - gpg binary (%s) not found\n - invalid signature\n - the signature key is not in the private keyring of UID %d,\n - there is no keyring in %s/.gnupg, or\n - the file is not signed - did you move /filename.asc to /filename ?\nTo create a signed file, use (remove old signatures before):\n gpg -a --clearsign --not-dash-escaped FILE\n mv FILE.asc FILE\n"), - DEFAULT_GPG_PATH, - (int) e_uid, e_home); - -#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R) - SH_FREE(e_buffer); -#endif - } - - TPT(((0), FIL__, __LINE__, _("msg=<Status = %d>\n"), status)); - - return (-1); /* make compiler happy */ -} - -#define FGETS_BUF 16384 - -SL_TICKET sh_gpg_extract_signed(SL_TICKET fd) -{ - FILE * fin_cp = NULL; - char * buf = NULL; - int bufc; - int flag_pgp = S_FALSE; - int flag_nohead = S_FALSE; - SL_TICKET fdTmp = (-1); - SL_TICKET open_tmp (void); - - /* extract the data and copy to temporary file - */ - fdTmp = open_tmp(); - if (SL_ISERROR(fdTmp)) - { - dlog(1, FIL__, __LINE__, _("Error opening temporary file.\n")); - sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, - _("Error opening temporary file."), - _("sh_gpg_extract_signed")); - return -1; - } - - fin_cp = fdopen(dup(get_the_fd(fd)), "rb"); - buf = SH_ALLOC(FGETS_BUF); - - while (NULL != fgets(buf, FGETS_BUF, fin_cp)) - { - bufc = 0; - while (bufc < FGETS_BUF) { - if (buf[bufc] == '\n') { ++bufc; break; } - ++bufc; - } - - if (flag_pgp == S_FALSE && - (0 == sl_strcmp(buf, _("-----BEGIN PGP SIGNED MESSAGE-----\n"))|| - 0 == sl_strcmp(buf, _("-----BEGIN PGP MESSAGE-----\n"))) - ) - { - flag_pgp = S_TRUE; - sl_write(fdTmp, buf, bufc); - continue; - } - - if (flag_pgp == S_TRUE && flag_nohead == S_FALSE) - { - if (buf[0] == '\n') - { - flag_nohead = S_TRUE; - sl_write(fdTmp, buf, 1); - continue; - } - else if (0 == sl_strncmp(buf, _("Hash:"), 5) || - 0 == sl_strncmp(buf, _("NotDashEscaped:"), 15)) - { - sl_write(fdTmp, buf, bufc); - continue; - } - else - continue; - } - - if (flag_pgp == S_TRUE && buf[0] == '\n') - { - sl_write(fdTmp, buf, 1); - } - else if (flag_pgp == S_TRUE) - { - /* sl_write_line(fdTmp, buf, bufc); */ - sl_write(fdTmp, buf, bufc); - } - - if (flag_pgp == S_TRUE && - 0 == sl_strcmp(buf, _("-----END PGP SIGNATURE-----\n"))) - break; - } - SH_FREE(buf); - sl_fclose(FIL__, __LINE__, fin_cp); /* fin_cp = fdopen(dup(), "rb"); */ - sl_rewind (fdTmp); - - return fdTmp; -} - -/* #ifdef WITH_GPG */ -#endif - - - - - - - - diff --git a/src/sh_hash.c b/src/sh_hash.c index 345475d..f1adec4 100644 --- a/src/sh_hash.c +++ b/src/sh_hash.c @@ -23,6 +23,9 @@ #include <string.h> #include <stdio.h> #include <sys/types.h> +#ifdef HAVE_SYS_SYSMACROS_H +#include <sys/sysmacros.h> +#endif #include <sys/stat.h> #include <unistd.h> #include <ctype.h> @@ -50,7 +53,7 @@ #include "sh_hash.h" #include "sh_error.h" #include "sh_tiger.h" -#include "sh_gpg.h" +#include "sh_sig.h" #include "sh_unix.h" #include "sh_files.h" #include "sh_ignore.h" @@ -1254,7 +1257,7 @@ char * sh_hash_db2pop (const char * key, struct store2db * save) ******************************************************************/ sh_file_t * sh_hash_push_int (file_type * buf, char * fileHash) { - sh_file_t * fp; + sh_file_t * fp = NULL; sh_filestore_t p; size_t len; @@ -1265,6 +1268,9 @@ sh_file_t * sh_hash_push_int (file_type * buf, char * fileHash) SL_ENTER(_("sh_hash_push_int")); + if (!buf) + SL_RETURN(NULL, _("sh_hash_push_int")); + fp = SH_ALLOC(sizeof(sh_file_t)); p.mark = REC_MAGIC; @@ -1806,6 +1812,9 @@ static int handle_notfound(int log_severity, int class, sh_file_t * p; int retval = 0; + if (!theFile) + return retval; + if (S_FALSE == sh_ignore_chk_new(theFile->fullpath)) { char * tmp = sh_util_safe_name(theFile->fullpath); @@ -1898,7 +1907,10 @@ int sh_hash_compdata (int class, file_type * theFile, char * fileHash, SL_ENTER(_("sh_hash_compdata")); - if (IsInit != 1) sh_hash_init(); + if (!theFile) + SL_RETURN(0, _("sh_hash_compdata")); + + if (IsInit != 1) sh_hash_init(); if (severity_override < 0) log_severity = ShDFLevel[class]; @@ -2018,7 +2030,7 @@ int sh_hash_compdata (int class, file_type * theFile, char * fileHash, TIGER_DATA, sl_strlen(theFile->link_path), hashbuf, sizeof(hashbuf)), - MAX_PATH_STORE+1); + sizeof(linkHash)); linkComp = linkHash; maxcomp = KEY_LEN; } @@ -2584,7 +2596,8 @@ int sh_hash_compdata (int class, file_type * theFile, char * fileHash, _("Fetching audit record"), _("sh_hash"), theFile->fullpath ); - if (NULL != sh_audit_fetch (theFile->fullpath, theFile->mtime, theFile->ctime, result, sizeof(result))) + if (NULL != sh_audit_fetch (theFile->fullpath, theFile->mtime, theFile->ctime, theFile->atime, + result, sizeof(result))) { #ifdef SH_USE_XML sl_strlcat(msg, _("obj=\""), SH_MSG_BUF); diff --git a/src/sh_inotify.c b/src/sh_inotify.c index 5fc8dab..6aa6582 100644 --- a/src/sh_inotify.c +++ b/src/sh_inotify.c @@ -235,7 +235,7 @@ ssize_t sh_inotify_read_timeout(char * buffer, size_t count, int timeout) ssize_t len; int ifd = sh_inotify_getfd(); - len = sl_read_timeout_fd (ifd, buffer, count, timeout, S_FALSE); + len = sl_read_timeout_fd_once (ifd, buffer, count, timeout, S_FALSE); return len; } diff --git a/src/sh_ipvx.c b/src/sh_ipvx.c index 84ceec9..41f23ef 100644 --- a/src/sh_ipvx.c +++ b/src/sh_ipvx.c @@ -200,6 +200,7 @@ char * sh_ipvx_print_sockaddr (struct sockaddr * sa, int sa_family) struct sh_sockaddr ss; static char ipbuf[SH_IP_BUF]; + memset(&ss, 0, sizeof(struct sh_sockaddr)); sh_ipvx_save(&ss, sa_family, sa); sh_ipvx_ntoa (ipbuf, sizeof(ipbuf), &ss); return ipbuf; @@ -207,8 +208,6 @@ char * sh_ipvx_print_sockaddr (struct sockaddr * sa, int sa_family) void sh_ipvx_save(struct sh_sockaddr * ss, int sa_family, struct sockaddr * sa) { - /* memset(ss, '\0', sizeof(struct sh_sockaddr)); */ - switch (sa_family) { case AF_INET: @@ -250,23 +249,22 @@ int sh_ipvx_set_port(struct sh_sockaddr * ss, int port) #endif } -int sh_ipvx_get_port(struct sockaddr * sa, int sa_family) +int sh_ipvx_get_port(struct sh_sockaddr * sa) { int port = 0; #if defined(USE_IPVX) - switch (sa_family) + switch (sa->ss_family) { case AF_INET: - port = ntohs(((struct sockaddr_in *)sa)->sin_port); + port = ntohs((sa->sin).sin_port); break; case AF_INET6: - port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port); + port = ntohs((sa->sin6).sin6_port); break; } #else - (void) sa_family; - port = ntohs(((struct sockaddr_in *)sa)->sin_port); + port = ntohs((sa->sin).sin_port); #endif return port; } @@ -278,7 +276,7 @@ int sh_ipvx_aton (const char * name, struct sh_sockaddr * ss) struct addrinfo hints; struct addrinfo *res; - memset(&hints, '\0', sizeof(hints)); + memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_NUMERICHOST; ret = getaddrinfo(name, NULL, &hints, &res); @@ -286,7 +284,7 @@ int sh_ipvx_aton (const char * name, struct sh_sockaddr * ss) if (ret) return 0; - memset(ss, '\0', sizeof(struct sh_sockaddr)); + memset(ss, 0, sizeof(struct sh_sockaddr)); switch(res->ai_family) { case AF_INET: @@ -301,6 +299,7 @@ int sh_ipvx_aton (const char * name, struct sh_sockaddr * ss) return 0; break; } + freeaddrinfo(res); return 1; #else int ret = inet_aton(name, &((ss->sin).sin_addr)); @@ -354,6 +353,8 @@ char * sh_ipvx_canonical(const char * hostname, char * numeric, size_t nlen) const char * host; char hostbuf[SH_BUFSIZE]; + SL_ENTER(_("sh_ipvx_canonical")); + numeric[0] = '\0'; sh_dummy_341_out = (void *) &out; @@ -381,6 +382,8 @@ char * sh_ipvx_canonical(const char * hostname, char * numeric, size_t nlen) err = getaddrinfo(host, NULL, &hints, &res); if (err == 0) { + struct addrinfo * res_orig = res; + #if defined(AI_CANONNAME) if (res->ai_canonname && strlen(res->ai_canonname) > 0) { @@ -412,6 +415,8 @@ char * sh_ipvx_canonical(const char * hostname, char * numeric, size_t nlen) res = res->ai_next; } + + freeaddrinfo(res_orig); } #else struct hostent *he; @@ -419,6 +424,8 @@ char * sh_ipvx_canonical(const char * hostname, char * numeric, size_t nlen) volatile int isNum = 0; struct sockaddr_in *sin; + SL_ENTER(_("sh_ipvx_canonical")); + numeric[0] = '\0'; sh_dummy_341_out = (void *) &out; @@ -454,14 +461,15 @@ char * sh_ipvx_canonical(const char * hostname, char * numeric, size_t nlen) SH_MUTEX_UNLOCK(mutex_resolv); #endif - if (flag) - return out; + if (flag) { + SL_RETURN(out, _("sh_ipvx_canonical")); + } if (out) SH_FREE(out); if (numeric[0] == '\0') sl_strlcpy (numeric, _("0.0.0.0"), nlen); - return NULL; + SL_RETURN(NULL, _("sh_ipvx_canonical")); } char * sh_ipvx_addrtoname(struct sh_sockaddr * ss) @@ -500,15 +508,17 @@ int sh_ipvx_reverse_check_ok (char * peer, int port, struct sh_sockaddr * ss) char sport[32]; struct addrinfo *p; + SL_ENTER(_("sh_ipvx_reverse_check_ok")); + sl_snprintf(sport, sizeof(sport), "%d", port); - memset(&hints, '\0', sizeof(hints)); + memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_ADDRCONFIG; if (getaddrinfo(peer, sport, &hints, &res) != 0) { - return 0; + SL_RETURN((0), _("sh_ipvx_reverse_check_ok")); } p = res; @@ -528,7 +538,7 @@ int sh_ipvx_reverse_check_ok (char * peer, int port, struct sh_sockaddr * ss) if (0 == sl_strcmp(dst1, dst2)) { - return 1; + SL_RETURN((1), _("sh_ipvx_reverse_check_ok")); } } p = p->ai_next; @@ -541,17 +551,19 @@ int sh_ipvx_reverse_check_ok (char * peer, int port, struct sh_sockaddr * ss) (void) port; + SL_ENTER(_("sh_ipvx_reverse_check_ok")); + he = sh_gethostbyname(peer); if (he != NULL) { for (p = he->h_addr_list; *p; ++p) { - if (0 == memcmp (*p, &(sin->sin_addr), sizeof(in_addr_t)) ) - return 1; + if (0 == memcmp (*p, &(sin->sin_addr), sizeof(in_addr_t)) ) { + SL_RETURN((1), _("sh_ipvx_reverse_check_ok")); } } } #endif - return 0; + SL_RETURN((0), _("sh_ipvx_reverse_check_ok")); } #ifdef SH_CUTEST diff --git a/src/sh_log_check.c b/src/sh_log_check.c index cc6fc4f..3114060 100644 --- a/src/sh_log_check.c +++ b/src/sh_log_check.c @@ -600,7 +600,7 @@ int sh_open_for_reader (struct sh_logfile * logfile) SH_FREE(tmp); SH_MUTEX_UNLOCK(mutex_thread_nolog); - memset (&(logfile->offset), '\0', sizeof(fpos_t)); + memset (&(logfile->offset), 0, sizeof(fpos_t)); logfile->flags |= SH_LOGFILE_REWIND; return 0; } @@ -622,7 +622,7 @@ int sh_open_for_reader (struct sh_logfile * logfile) { /* done with rotated file, start with current file */ - memset (&(logfile->offset), '\0', sizeof(fpos_t)); + memset (&(logfile->offset), 0, sizeof(fpos_t)); logfile->flags |= SH_LOGFILE_REWIND; logfile->flags &= ~SH_LOGFILE_MOVED; logfile->inode = buf.st_ino; @@ -645,7 +645,7 @@ int sh_open_for_reader (struct sh_logfile * logfile) } else { - memset (&(logfile->offset), '\0', sizeof(fpos_t)); + memset (&(logfile->offset), 0, sizeof(fpos_t)); logfile->flags |= SH_LOGFILE_REWIND; logfile->inode = buf.st_ino; logfile->device_id = buf.st_dev; @@ -964,7 +964,7 @@ sh_string * sh_binary_reader (void * s, size_t size, if (status != 1) { - memset(s, '\0', size); + memset(s, 0, size); if (ferror(logfile->fp) && (logfile->flags & SH_LOGFILE_PIPE) == 0) { char * tmp; diff --git a/src/sh_log_evalrule.c b/src/sh_log_evalrule.c index 98a36d0..b053975 100644 --- a/src/sh_log_evalrule.c +++ b/src/sh_log_evalrule.c @@ -185,7 +185,7 @@ int sh_eval_gadd (const char * str) group_extra = NULL; /* pcre_study(group, 0, &error); */ ng = SH_ALLOC(sizeof(struct sh_geval)); - memset(ng, '\0', sizeof(struct sh_geval)); + memset(ng, 0, sizeof(struct sh_geval)); ng->label = sh_string_new_from_lchar(splits[0], lengths[0]); ng->flags = RFL_ISGROUP; @@ -293,7 +293,7 @@ int sh_eval_hadd (const char * str) host_extra = NULL; /* pcre_study(host, 0, &error); */ nh = SH_ALLOC(sizeof(struct sh_heval)); - memset(nh, '\0', sizeof(struct sh_heval)); + memset(nh, 0, sizeof(struct sh_heval)); nh->hostname = host; nh->hostname_extra = host_extra; @@ -361,7 +361,7 @@ int sh_eval_qadd (const char * str) } nq = SH_ALLOC(sizeof(struct sh_qeval)); - memset(nq, '\0', sizeof(struct sh_qeval)); + memset(nq, 0, sizeof(struct sh_qeval)); nq->label = sh_string_new_from_lchar(splits[0], lengths[0]); nq->alias = NULL; @@ -457,7 +457,7 @@ static char * get_label_and_time(const char * inprefix, char * str, if (splits && nfields == 2 && lengths[0] > 0 && lengths[1] > 0) { *seconds = strtoul(splits[0], &endptr, 10); - if ((endptr == '\0' || endptr != splits[0]) && (*seconds != ULONG_MAX)) + if ((*endptr == '\0') && (endptr != splits[0]) && (*seconds != ULONG_MAX)) { res = sh_util_strdup(splits[1]); } @@ -494,6 +494,9 @@ int sh_eval_radd (const char * str) char * s = new; volatile char pflag = '-'; + if (s == NULL) + return -1; + /* cppcheck-suppress uninitdata */ while ( *s && isspace((int)*s) ) ++s; if (0 == strncmp(s, _("KEEP"), 4) || 0 == strncmp(s, _("CORRELATE"), 9) || @@ -616,7 +619,7 @@ int sh_eval_radd (const char * str) SH_FREE(new); nr = SH_ALLOC(sizeof(struct sh_geval)); - memset(nr, '\0', sizeof(struct sh_geval)); + memset(nr, 0, sizeof(struct sh_geval)); nr->label = NULL; nr->flags = RFL_ISRULE; @@ -1138,7 +1141,7 @@ static struct sh_ceval * find_counter(struct sh_geval * rule, DEBUG("debug: no counter found\n"); counter = SH_ALLOC(sizeof(struct sh_ceval)); - memset(counter, '\0', sizeof(struct sh_ceval)); + memset(counter, 0, sizeof(struct sh_ceval)); counter->hostname = sh_string_new_from_lchar(sh_string_str(host), sh_string_len(host)); diff --git a/src/sh_log_parse_apache.c b/src/sh_log_parse_apache.c index 06cdf4e..5e40aab 100644 --- a/src/sh_log_parse_apache.c +++ b/src/sh_log_parse_apache.c @@ -353,7 +353,7 @@ struct sh_logrecord * sh_parse_apache (sh_string * logline, void * fileinfo) struct tm btime; char * ptr = NULL; - memset(&btime, '\0', sizeof(struct tm)); + memset(&btime, 0, sizeof(struct tm)); btime.tm_isdst = -1; /* example: 01/Jun/2008:07:55:28 +0200 */ diff --git a/src/sh_log_parse_samba.c b/src/sh_log_parse_samba.c index 820bbe3..e84302a 100644 --- a/src/sh_log_parse_samba.c +++ b/src/sh_log_parse_samba.c @@ -74,7 +74,7 @@ struct sh_logrecord * sh_parse_samba (sh_string * logline, void * fileinfo) struct tm btime; char * ptr; - memset(&btime, '\0', sizeof(struct tm)); + memset(&btime, 0, sizeof(struct tm)); btime.tm_isdst = -1; ptr = strptime(sh_string_str(logline), format_1, &btime); diff --git a/src/sh_log_parse_syslog.c b/src/sh_log_parse_syslog.c index ae9f801..167abd2 100644 --- a/src/sh_log_parse_syslog.c +++ b/src/sh_log_parse_syslog.c @@ -93,7 +93,7 @@ struct sh_logrecord * sh_parse_syslog (sh_string * logline, void * fileinfo) int flag; size_t lengths[3]; - memset(&btime, '\0', sizeof(struct tm)); + memset(&btime, 0, sizeof(struct tm)); btime.tm_isdst = -1; /* This is RFC 3164. diff --git a/src/sh_log_repeat.c b/src/sh_log_repeat.c index 9285c82..1125662 100644 --- a/src/sh_log_repeat.c +++ b/src/sh_log_repeat.c @@ -58,11 +58,15 @@ static int free_slots = 0; /* free slots available */ #define SH_CLEANUP 256 +void * sh_dummy_g_array = NULL; + static struct gestalt * add_entry (unsigned char * flags, UINT16 * sum, time_t ltime) { struct gestalt * array = NULL; + sh_dummy_g_array = (void*) &array; + start: if (urec < nrec) { @@ -164,6 +168,8 @@ static struct gestalt * update_or_add (unsigned char * flags, UINT16 * sum, unsigned int i; struct gestalt * array = arec; + sh_dummy_g_array = (void*) &array; + memcpy(flint, flags, SH_NFIELDS); for (i = 0; i < urec; ++i) diff --git a/src/sh_login_track.c b/src/sh_login_track.c index 854df9e..7df22fe 100644 --- a/src/sh_login_track.c +++ b/src/sh_login_track.c @@ -231,7 +231,7 @@ static struct sh_track * load_data_int (char * path) struct sh_track * urecord; urecord = SH_ALLOC(sizeof(struct sh_track)); - memset(urecord, '\0', sizeof(struct sh_track)); + memset(urecord, 0, sizeof(struct sh_track)); uhead = &(urecord->head); uhead->version = SH_LTRACK_VERSION; @@ -401,7 +401,7 @@ static struct sh_track_dates * find_user(const char * user) while(u) { - if (0 == strcmp(user, u->user)) + if (0 == sl_strcmp(user, u->user)) { return u; } @@ -444,7 +444,7 @@ int sh_login_set_user_allow(const char * c) if (!u) { u = SH_ALLOC(sizeof(struct sh_track_dates)); - memset(u, '\0', sizeof(struct sh_track_dates)); + memset(u, 0, sizeof(struct sh_track_dates)); sl_strlcpy(u->user, user, SH_LTRACK_USIZE); flag = 1; } @@ -838,15 +838,17 @@ static char * stripped_hostname (const char * host) } else { - q = strchr(host, '.'); + char * tmp = sh_util_strdup(host); + q = strchr(tmp, '.'); if (q && *q) { ++q; p = sh_util_strdup(q); + SH_FREE(tmp); } else { - p = sh_util_strdup(host); + p = tmp; } } return p; @@ -912,7 +914,7 @@ static struct sh_track_entry * check_host(struct sh_track_entry * list, else { entry = SH_ALLOC(sizeof(struct sh_track_entry)); - memset(entry, '\0', sizeof(struct sh_track_entry)); + memset(entry, 0, sizeof(struct sh_track_entry)); (entry->data).last_login = time; (entry->data).array[index] = 1; sl_strlcpy((entry->data).hostname, q, SH_LTRACK_HSIZE); diff --git a/src/sh_mem.c b/src/sh_mem.c index 453640f..6d402fa 100644 --- a/src/sh_mem.c +++ b/src/sh_mem.c @@ -76,20 +76,25 @@ unsigned long Mem_Current = 0, Mem_Max = 0; SH_MUTEX_RECURSIVE(mutex_mem); #endif -/* define MEM_LOG to an absolute filename to enable this */ +/* define MEM_LOG to enable this */ +/* #define MEM_LOG 1 */ #ifdef MEM_LOG void sh_mem_dump () { memlist_t * this = memlist; FILE * fd; + static unsigned int nr = 0; + char filename[256]; + snprintf(filename, sizeof(filename), "sh_mem_dump.%04u.%lu", nr, (unsigned long) sh.pid); + SH_MUTEX_RECURSIVE_INIT(mutex_mem); SH_MUTEX_RECURSIVE_LOCK(mutex_mem); - fd = fopen(MEM_LOG, "w"); + fd = fopen(filename, "w"); if (!fd) { - perror(MEM_LOG); + perror(filename); _exit(EXIT_FAILURE); } @@ -102,7 +107,9 @@ void sh_mem_dump () sl_fclose(FIL__, __LINE__, fd); SH_MUTEX_RECURSIVE_UNLOCK(mutex_mem); - _exit(EXIT_SUCCESS); + ++nr; + /* _exit(EXIT_SUCCESS); */ + return; } #else void sh_mem_dump () @@ -317,8 +324,8 @@ void * sh_mem_malloc (size_t size, char * file, int line) SL_RETURN( theAddress, _("sh_mem_malloc")); } -static void ** sh_mem_dummy_a; -static memlist_t ** sh_mem_merr_3; +void ** sh_mem_dummy_a; +memlist_t ** sh_mem_merr_3; void sh_mem_free (void * aa, char * file, int line) { diff --git a/src/sh_mounts.c b/src/sh_mounts.c index 736fa7b..51429eb 100644 --- a/src/sh_mounts.c +++ b/src/sh_mounts.c @@ -397,7 +397,7 @@ int sh_mounts_config_sevopt (const char * opt) */ /* FreeBSD includes */ -#if defined(HOST_IS_FREEBSD) || defined(HOST_IS_OPENBSD) +#if defined(HOST_IS_FREEBSD) || defined(HOST_IS_OPENBSD) || defined(HOST_IS_DARWIN) #include <sys/param.h> #include <sys/ucred.h> #include <sys/mount.h> @@ -571,10 +571,10 @@ static int aix_fs_get (FILE *fd, AixMountTableEntry *prop) } /* end AIX helper routines */ -#endif +#endif #endif -#if defined(HOST_IS_FREEBSD) || defined(HOST_IS_OPENBSD) +#if defined(HOST_IS_FREEBSD) || defined(HOST_IS_OPENBSD) || defined(HOST_IS_DARWIN) /* FreeBSD returns flags instead of strings as mount options, so we'll convert * them here. */ @@ -682,7 +682,7 @@ static struct sh_mounts_mnt * readmounts(void) { list = m; /* The Open/FreeBSD way */ -#if defined(HOST_IS_FREEBSD) || defined(HOST_IS_OPENBSD) +#if defined(HOST_IS_FREEBSD) || defined(HOST_IS_OPENBSD) || defined(HOST_IS_DARWIN) { struct statfs *fsp; int entries; diff --git a/src/sh_port2proc.c b/src/sh_port2proc.c index 61357f1..7289ef8 100644 --- a/src/sh_port2proc.c +++ b/src/sh_port2proc.c @@ -634,7 +634,7 @@ static void * xrealloc(void * buf, size_t len0, size_t len) if (len0 <= len) memcpy(xbuf, buf, len0); else - memset(xbuf, '\0', len); + memset(xbuf, 0, len); SH_FREE(buf); } return xbuf; @@ -822,7 +822,7 @@ gather_inet(int proto) } sock = SH_ALLOC(sizeof *sock); - memset(sock, '\0', sizeof (*sock)); + memset(sock, 0, sizeof (*sock)); #ifndef in6p_lport #define in6p_lport inp_lport diff --git a/src/sh_portcheck.c b/src/sh_portcheck.c index 507f028..106d9cb 100644 --- a/src/sh_portcheck.c +++ b/src/sh_portcheck.c @@ -32,15 +32,20 @@ #include <stdio.h> #include <string.h> +#include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> +#ifdef HAVE_IFADDRS_H +#include <ifaddrs.h> +#include <netdb.h> +#endif #include <errno.h> #include <unistd.h> #include <fcntl.h> -#define PORTCHK_VERSION "1.0" +#define PORTCHK_VERSION "1.1" #if defined(TEST_ONLY) || (defined(SH_USE_PORTCHECK) && (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE))) @@ -134,9 +139,11 @@ static struct sh_portentry * portlist_udp = NULL; #define SH_PORTCHK_INTERVAL 300 -static int sh_portchk_check_udp = 1; -static int sh_portchk_active = 1; -static int sh_portchk_interval = SH_PORTCHK_INTERVAL; +static int sh_portchk_check_udp = 1; +static int sh_portchk_active = 1; +static int sh_portchk_same_ports = 1; +static int sh_portchk_transients = 1; +static int sh_portchk_interval = SH_PORTCHK_INTERVAL; static int sh_portchk_minport = -1; static int sh_portchk_maxport = -1; @@ -150,6 +157,9 @@ struct sh_port { static struct sh_port * blacklist_tcp = NULL; static struct sh_port * blacklist_udp = NULL; +static struct sh_port * transient_tcp = NULL; +static struct sh_port * transient_udp = NULL; + SH_MUTEX_STATIC(mutex_port_check, PTHREAD_MUTEX_INITIALIZER); static int sh_portchk_severity = SH_ERR_SEVERE; @@ -181,10 +191,21 @@ static int sh_portchk_add_blacklist (const char * str); */ static int sh_portchk_add_interface (const char * str); +#if defined(HAVE_IFADDRS_H) +/* Exported interface to add an ethernet device + */ +static int sh_portchk_add_device (const char * str); +#endif + /* verify whether port/interface is blacklisted (do not check) */ static int sh_portchk_is_blacklisted(int port, struct sh_sockaddr * haddr, int proto); +/* verify whether port/interface is transient (used as source port hence no check required) + */ +static int sh_portchk_is_transient(int port, struct sh_sockaddr * haddr, int proto); +static int sh_portchk_transient(int port, struct sh_sockaddr * haddr, int proto); + #ifndef TEST_ONLY static int sh_portchk_set_interval (const char * c) @@ -232,27 +253,37 @@ static int sh_portchk_set_port_minmax (const char * c, int * setthis) } -static int sh_portchk_set_minport (const char * str) +static int sh_portchk_set_minport (const char * str) { return sh_portchk_set_port_minmax (str, &sh_portchk_minport); } -static int sh_portchk_set_maxport (const char * str) +static int sh_portchk_set_maxport (const char * str) { return sh_portchk_set_port_minmax (str, &sh_portchk_maxport); } -static int sh_portchk_set_active (const char * str) +static int sh_portchk_set_active (const char * str) { return sh_util_flagval(str, &sh_portchk_active); } -static int sh_portchk_set_udp (const char * str) +static int sh_portchk_set_udp (const char * str) { return sh_util_flagval(str, &sh_portchk_check_udp); } +#if defined(SH_ALLOW_RESTORE) +static int sh_portchk_set_transients (const char * str) +{ + return sh_util_flagval(str, &sh_portchk_transients); +} -static int sh_portchk_set_severity (const char * str) +static int sh_portchk_set_same_ports (const char * str) +{ + return sh_util_flagval(str, &sh_portchk_same_ports); +} +#endif +static int sh_portchk_set_severity (const char * str) { char tmp[32]; tmp[0] = '='; tmp[1] = '\0'; @@ -285,6 +316,12 @@ sh_rconf sh_portchk_table[] = { N_("portcheckactive"), sh_portchk_set_active, }, +#if defined(HAVE_IFADDRS_H) + { + N_("portcheckdevice"), + sh_portchk_add_device, + }, +#endif { N_("portcheckinterface"), sh_portchk_add_interface, @@ -305,6 +342,16 @@ sh_rconf sh_portchk_table[] = { N_("portcheckudp"), sh_portchk_set_udp, }, +#if defined(SH_ALLOW_RESTORE) + { + N_("portchecktransients"), + sh_portchk_set_transients, + }, + { + N_("portchecksameports"), + sh_portchk_set_same_ports, + }, +#endif { NULL, NULL @@ -382,6 +429,7 @@ static char * sh_getrpcbynumber (int number, char * buf, size_t len) sh_string_destroy(&s); sl_fclose(FIL__, __LINE__, fp); } + /* cppcheck-suppress resourceLeak */ return NULL; } #endif @@ -432,6 +480,7 @@ static char * sh_getservbyport (int port, const char * proto_in, char * buf, siz sh_string_destroy(&s); sl_fclose(FIL__, __LINE__, fp); } + /* cppcheck-suppress resourceLeak */ return NULL; } @@ -523,6 +572,19 @@ static struct sh_port * sh_portchk_kill_blacklist (struct sh_port * head) return NULL; } +static struct sh_port * sh_portchk_kill_transient (struct sh_port * head) +{ + if (head) + { + if (head->next) + sh_portchk_kill_transient (head->next); + + SH_FREE(head->paddr); + SH_FREE(head); + } + return NULL; +} + /* These variables are not used anywhere. They only exist * to assign &pre, &ptr to them, which keeps gcc from * putting it into a register, and avoids the 'clobbered @@ -538,7 +600,7 @@ static void sh_portchk_check_list (struct sh_portentry ** head, { struct sh_portentry * ptr = *head; struct sh_portentry * pre = *head; - char errbuf[256]; + char errbuf[512]; /* Take the address to keep gcc from putting them into registers. * Avoids the 'clobbered by longjmp' warning. @@ -629,6 +691,7 @@ static struct sh_portentry * sh_portchk_get_from_list (int proto, int port, struct sh_portentry * portlist; char str_addr[SH_IP_BUF]; + if (proto == IPPROTO_TCP) portlist = portlist_tcp; else @@ -667,7 +730,7 @@ static void sh_portchk_cmp_to_list (int proto, int port, struct sh_sockaddr * paddr, char * service) { struct sh_portentry * portent; - char errbuf[256]; + char errbuf[512]; portent = sh_portchk_get_from_list (proto, port, paddr, service); @@ -886,6 +949,9 @@ static char * check_rpc_list (int port, struct sockaddr_in * address, return NULL; } +void * sh_dummy_950_p = NULL; +void * sh_dummy_951_p = NULL; + static int check_port_udp_internal (int fd, int port, struct sh_sockaddr * paddr) { int retval; @@ -893,11 +959,17 @@ static int check_port_udp_internal (int fd, int port, struct sh_sockaddr * paddr char buf[8]; #ifndef TEST_ONLY char errmsg[256]; - int nerr; + volatile int nerr; #endif char errbuf[SH_ERRBUF_SIZE]; char ipbuf[SH_IP_BUF]; + struct sh_sockaddr saddr; + socklen_t slen = 0; + volatile int sport = 0; + + sh_dummy_950_p = (void*) &p; + sh_ipvx_set_port(paddr, port); do { @@ -923,85 +995,155 @@ static int check_port_udp_internal (int fd, int port, struct sh_sockaddr * paddr } else { - do { - retval = send (fd, buf, 0, 0); - } while (retval < 0 && errno == EINTR); + /* Register the used source port as transient. This will avoid + * the issue of lingering source ports being reported as a spurious + * service. The lingering source port is effectvely a race condition. + * + * Also use this code to obtain the source port. Sometimes Samhain + * reports on a port where it connects back to itself. In that case + * source and destination port are the same. + * + * AGH, 23 Apr 2017 (www.2024sight.com). + */ - if (retval == -1 && errno == ECONNREFUSED) - { - sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr); - if (portchk_debug) - fprintf(stderr, _("check port_udp: %5d/udp on %15s established/time_wait\n"), - port, ipbuf); - } - else - { - /* Only the second send() may catch the error - */ - do { +#if defined(USE_IPVX) + if (paddr->ss_family == AF_INET) + { + saddr.ss_family = AF_INET; + slen = sizeof( struct sockaddr_in ); + retval = getsockname(fd, (struct sockaddr *)&(saddr.sin), &slen); + } + else + { + saddr.ss_family = AF_INET6; + slen = sizeof( struct sockaddr_in6 ); + retval = getsockname(fd, (struct sockaddr *)&(saddr.sin6), &slen); + } +#else + saddr.ss_family = AF_INET; + slen = sizeof( struct sockaddr_in ); + retval = getsockname(fd, (struct sockaddr *)&(saddr.sin), &slen); +#endif + + if ( retval == 0 ) + { + sport = sh_ipvx_get_port(&saddr); + sh_portchk_transient(sport, &saddr, IPPROTO_UDP); + } + else + { +#ifdef TEST_ONLY + if (portchk_debug) + perror(_("getsockname")); +#else + sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr); + nerr = errno; + sl_snprintf(errmsg, sizeof(errmsg), _("source port transient for %15s:%d/udp: %s"), + ipbuf, port, sh_error_message(errno, errbuf, sizeof(errbuf))); + SH_MUTEX_LOCK(mutex_thread_nolog); + sh_error_handle((-1), FIL__, __LINE__, nerr, MSG_E_SUBGEN, errmsg, _("getsockname")); + SH_MUTEX_UNLOCK(mutex_thread_nolog); +#endif + } + + if (( sport != port ) || ( sh_portchk_same_ports == S_FALSE )) + { + do { retval = send (fd, buf, 0, 0); - } while (retval < 0 && errno == EINTR); + } while (retval < 0 && errno == EINTR); - if (retval == -1 && errno == ECONNREFUSED) + if (retval == -1 && errno == ECONNREFUSED) { sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr); if (portchk_debug) - fprintf(stderr, _("check port: %5d/udp on %15s established/time_wait\n"), - port, ipbuf); + fprintf(stderr, _("check port_udp: %5d/udp on %15s established/time_wait\n"), + port, ipbuf); } - else if (retval != -1) + else { - /* Try to get service name from portmap + /* Only the second send() may catch the error */ - if (paddr->ss_family == AF_INET) - { - p = check_rpc_list (port, - (struct sockaddr_in *) sh_ipvx_sockaddr_cast(paddr), - IPPROTO_UDP); - } + do { + retval = send (fd, buf, 0, 0); + } while (retval < 0 && errno == EINTR); + + if (retval == -1 && errno == ECONNREFUSED) + { + sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr); + if (portchk_debug) + fprintf(stderr, _("check port: %5d/udp on %15s established/time_wait\n"), + port, ipbuf); + } + else if (retval != -1) + { + /* Try to get service name from portmap + */ + if (paddr->ss_family == AF_INET) + { + p = check_rpc_list (port, + (struct sockaddr_in *) sh_ipvx_sockaddr_cast(paddr), + IPPROTO_UDP); + } - sh_portchk_cmp_to_list (IPPROTO_UDP, port, paddr, p ? p : NULL); + sh_portchk_cmp_to_list (IPPROTO_UDP, port, paddr, p ? p : NULL); - /* If not an RPC service, try to get name from /etc/services - */ - if (!p) - p = check_services(port, IPPROTO_UDP); + /* If not an RPC service, try to get name from /etc/services + */ + if (!p) + p = check_services(port, IPPROTO_UDP); - if (portchk_debug) - { - sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr); - fprintf(stderr, _("check port_udp: %5d/udp on %15s open %s\n"), - port, ipbuf, p); - } + if (portchk_debug) + { + sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr); + fprintf(stderr, _("check port_udp: %5d/udp on %15s open %s\n"), + port, ipbuf, p); + } + } + else + { + if (portchk_debug) + { + sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr); + fprintf(stderr, _("check port_udp: %5d/udp on %15s ERRNO %d\n"), + port, ipbuf, errno); + } + } } - else - { - if (portchk_debug) - { - sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr); - fprintf(stderr, _("check port_udp: %5d/udp on %15s ERRNO %d\n"), - port, ipbuf, errno); - } - } - } + } + else + { + if (portchk_debug) + { + sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr); + fprintf(stderr, _("check port_udp: %5d/udp on %15s same source and destination port\n"), + port, ipbuf); + } + } } sl_close_fd (FIL__, __LINE__, fd); + sh_dummy_950_p = NULL; return 0; } static int check_port_tcp_internal (int fd, int port, struct sh_sockaddr * paddr) { - int retval; + volatile int retval; int flags; char * p = NULL; #ifndef TEST_ONLY char errmsg[256]; - int nerr; + volatile int nerr; #endif char errbuf[SH_ERRBUF_SIZE]; char ipbuf[SH_IP_BUF]; + struct sh_sockaddr saddr; + socklen_t slen = 0; + volatile int sport = 0; + + sh_dummy_951_p = (void*) &p; + sh_ipvx_set_port(paddr, port); do { @@ -1035,28 +1177,92 @@ static int check_port_tcp_internal (int fd, int port, struct sh_sockaddr * paddr } else { - /* Try to get service name from portmap + /* Register the used source port as transient. This will avoid + * the issue of lingering source ports being reported as a spurious + * service. The lingering source port is effectively a race condition. + * + * Also use this code to obtain the source port. Sometimes Samhain + * reports on a port where it connects back to itself. In that case + * source and destination port are the same. + * + * AGH, 23 Apr 2017 (www.2024sight.com). */ + +#if defined(USE_IPVX) if (paddr->ss_family == AF_INET) - { - p = check_rpc_list (port, - (struct sockaddr_in *) sh_ipvx_sockaddr_cast(paddr), - IPPROTO_TCP); - } + { + saddr.ss_family = AF_INET; + slen = sizeof( struct sockaddr_in ); + retval = getsockname(fd, (struct sockaddr *)&(saddr.sin), &slen); + } + else + { + saddr.ss_family = AF_INET6; + slen = sizeof( struct sockaddr_in6 ); + retval = getsockname(fd, (struct sockaddr *)&(saddr.sin6), &slen); + } +#else + saddr.ss_family = AF_INET; + slen = sizeof( struct sockaddr_in ); + retval = getsockname(fd, (struct sockaddr *)&(saddr.sin), &slen); +#endif + + if ( retval == 0 ) + { + sport = sh_ipvx_get_port(&saddr); + sh_portchk_transient(sport, &saddr, IPPROTO_TCP); + } + else + { +#ifdef TEST_ONLY + if (portchk_debug) + perror(_("getsockname")); +#else + sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr); + nerr = errno; + sl_snprintf(errmsg, sizeof(errmsg), _("source port transient for %15s:%d/tcp: %s"), + ipbuf, port, sh_error_message(errno, errbuf, sizeof(errbuf))); + SH_MUTEX_LOCK(mutex_thread_nolog); + sh_error_handle((-1), FIL__, __LINE__, nerr, MSG_E_SUBGEN, + errmsg, _("getsockname")); + SH_MUTEX_UNLOCK(mutex_thread_nolog); +#endif + } - sh_portchk_cmp_to_list (IPPROTO_TCP, port, paddr, p ? p : NULL); + if (( sport != port ) || ( sh_portchk_same_ports == S_FALSE )) + { + /* Try to get service name from portmap + */ + if (paddr->ss_family == AF_INET) + { + p = check_rpc_list (port, + (struct sockaddr_in *) sh_ipvx_sockaddr_cast(paddr), + IPPROTO_TCP); + } - /* If not an RPC service, try to get name from /etc/services - */ - if (!p) - p = check_services(port, IPPROTO_TCP); + sh_portchk_cmp_to_list (IPPROTO_TCP, port, paddr, p ? p : NULL); - if (portchk_debug) - { - sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr); - fprintf(stderr, _("check port_tcp: %5d on %15s open %s\n"), - port, ipbuf, p); - } + /* If not an RPC service, try to get name from /etc/services + */ + if (!p) + p = check_services(port, IPPROTO_TCP); + + if (portchk_debug) + { + sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr); + fprintf(stderr, _("check port_tcp: %5d on %15s open %s\n"), + port, ipbuf, p); + } + } + else + { + if (portchk_debug) + { + sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), paddr); + fprintf(stderr, _("check port_udp: %5d/tcp on %15s same source and destination port\n"), + port, ipbuf); + } + } #if !defined(O_NONBLOCK) #if defined(O_NDELAY) @@ -1108,6 +1314,7 @@ static int check_port_tcp_internal (int fd, int port, struct sh_sockaddr * paddr port); } sl_close_fd (FIL__, __LINE__, fd); + sh_dummy_951_p = NULL; return 0; } @@ -1118,14 +1325,17 @@ static int check_port_tcp_internal (int fd, int port, struct sh_sockaddr * paddr * }; */ -#define SH_IFACE_MAX 16 +#define SH_IFACE_MAX 64 +#define SH_IFACE_ADDR 0 +#define SH_IFACE_DEV 1 struct portchk_interfaces { - struct sh_sockaddr iface[SH_IFACE_MAX]; - int used; + struct sh_sockaddr iface; + int type; }; -static struct portchk_interfaces iface_list; +static struct portchk_interfaces iface_list[SH_IFACE_MAX]; +static int iface_list_used = 0; static int iface_initialized = 0; #ifdef TEST_ONLY @@ -1158,7 +1368,7 @@ static int sh_portchk_init_internal (void) SH_MUTEX_LOCK(mutex_port_check); if (iface_initialized == 0) { - iface_list.used = 0; + iface_list_used = 0; iface_initialized = 1; } @@ -1166,7 +1376,7 @@ static int sh_portchk_init_internal (void) SH_MUTEX_LOCK(mutex_resolv); hent = sh_gethostbyname(portchk_hostname); i = 0; - while (hent && hent->h_addr_list[i] && (iface_list.used < SH_IFACE_MAX)) + while (hent && hent->h_addr_list[i] && (iface_list_used < SH_IFACE_MAX)) { struct sockaddr_in sin; struct sh_sockaddr iface_tmp; @@ -1174,31 +1384,32 @@ static int sh_portchk_init_internal (void) memcpy(&(sin.sin_addr.s_addr), hent->h_addr_list[i], sizeof(in_addr_t)); sh_ipvx_save(&iface_tmp, AF_INET, (struct sockaddr *)&sin); - for (j = 0; j < iface_list.used; ++j) + for (j = 0; j < iface_list_used; ++j) { - if (0 == sh_ipvx_cmp(&iface_tmp, &(iface_list.iface[j]))) + if (0 == sh_ipvx_cmp(&iface_tmp, &(iface_list[j].iface))) { goto next_iface; } } - sh_ipvx_save(&(iface_list.iface[iface_list.used]), + sh_ipvx_save(&(iface_list[iface_list_used].iface), AF_INET, (struct sockaddr *)&sin); + iface_list[iface_list_used].type = SH_IFACE_ADDR; if (portchk_debug) { char buf[256]; - sh_ipvx_ntoa(buf, sizeof(buf), &(iface_list.iface[iface_list.used])); + sh_ipvx_ntoa(buf, sizeof(buf), &(iface_list[iface_list_used].iface)); fprintf(stderr, _("added interface[%d]: %s\n"), i, buf); } - ++iface_list.used; + ++iface_list_used; next_iface: ++i; } SH_MUTEX_UNLOCK(mutex_resolv); #else - memset(&hints, '\0', sizeof(hints)); + memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_ADDRCONFIG; @@ -1207,37 +1418,37 @@ static int sh_portchk_init_internal (void) struct addrinfo *p = res; struct sh_sockaddr iface_tmp; - while ((p != NULL) && (iface_list.used < SH_IFACE_MAX)) + while ((p != NULL) && (iface_list_used < SH_IFACE_MAX)) { sh_ipvx_save(&iface_tmp, p->ai_family, p->ai_addr); - for (j = 0; j < iface_list.used; ++j) + for (j = 0; j < iface_list_used; ++j) { if (portchk_debug) { char buf1[256], buf2[256]; - sh_ipvx_ntoa(buf1, sizeof(buf1), &(iface_list.iface[j])); + sh_ipvx_ntoa(buf1, sizeof(buf1), &(iface_list[j].iface)); sh_ipvx_ntoa(buf2, sizeof(buf2), &iface_tmp); fprintf(stderr, _("check interface[%d]: %s vs %s\n"), j, buf1, buf2); } - if (0 == sh_ipvx_cmp(&iface_tmp, &(iface_list.iface[j]))) + if (0 == sh_ipvx_cmp(&iface_tmp, &(iface_list[j].iface))) { if (portchk_debug) fprintf(stderr, _("skipping interface[%d]\n"), j); goto next_iface; } } - sh_ipvx_save(&(iface_list.iface[iface_list.used]), + sh_ipvx_save(&(iface_list[iface_list_used].iface), p->ai_family, p->ai_addr); - + iface_list[iface_list_used].type = SH_IFACE_ADDR; if (portchk_debug) { char buf[256]; - sh_ipvx_ntoa(buf, sizeof(buf), &(iface_list.iface[iface_list.used])); - fprintf(stderr, _("added interface[%d]: %s\n"), iface_list.used, buf); + sh_ipvx_ntoa(buf, sizeof(buf), &(iface_list[iface_list_used].iface)); + fprintf(stderr, _("added interface[%d]: %s\n"), iface_list_used, buf); } - ++iface_list.used; + ++iface_list_used; next_iface: p = p->ai_next; @@ -1246,9 +1457,9 @@ static int sh_portchk_init_internal (void) } #endif - for (i = 0; i < iface_list.used; ++i) + for (i = 0; i < iface_list_used; ++i) { - sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), &(iface_list.iface[i])); + sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), &(iface_list[i].iface)); sl_snprintf(errbuf, sizeof(errbuf), _("added interface: %s"), ipbuf); SH_MUTEX_LOCK(mutex_thread_nolog); @@ -1284,13 +1495,14 @@ int sh_portchk_init (struct mod_type * arg) else if (arg != NULL && arg->initval == SH_MOD_THREAD && (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE)) { + (void) sh_portchk_init_internal(); return SH_MOD_THREAD; } #endif return sh_portchk_init_internal(); } - +static void dev_list_kill(); #if !defined(TEST_ONLY) int sh_portchk_reconf (void) @@ -1304,6 +1516,8 @@ int sh_portchk_reconf (void) sh_portchk_minport = -1; sh_portchk_maxport = -1; + dev_list_kill(); + portlist_udp = sh_portchk_kill_list (portlist_udp); portlist_tcp = sh_portchk_kill_list (portlist_tcp); @@ -1344,9 +1558,9 @@ static int check_port_generic (int port, int domain, int type, int protocol) /* Check all interfaces for this host */ - while (i < iface_list.used) + while (i < iface_list_used) { - memcpy(&paddr, &(iface_list.iface[i]), sizeof(paddr)); + memcpy(&paddr, &(iface_list[i].iface), sizeof(paddr)); if (paddr.ss_family != domain) { @@ -1360,6 +1574,12 @@ static int check_port_generic (int port, int domain, int type, int protocol) continue; } + if (0 != sh_portchk_is_transient(port, &paddr, protocol)) + { + ++i; + continue; + } + if ((sock = socket(paddr.ss_family, type, protocol)) < 0 ) { ++i; @@ -1549,6 +1769,12 @@ static int sh_portchk_scan_ports_generic (int min_port, int max_port_arg, sl_close_fd (FIL__, __LINE__, sock); } } + + if (protocol == IPPROTO_TCP) + transient_tcp=sh_portchk_kill_transient(transient_tcp); + else + transient_udp=sh_portchk_kill_transient(transient_udp); + return 0; } @@ -1576,7 +1802,7 @@ static int sh_portchk_scan_ports_udp (int min_port, int max_port) */ void * sh_dummy_1564_str = NULL; /* fix clobbered by.. warning */ -static int sh_portchk_add_interface (const char * str) +static int sh_portchk_add_interface_int (const char * str, int type) { struct sh_sockaddr saddr; char errbuf[256]; @@ -1586,7 +1812,7 @@ static int sh_portchk_add_interface (const char * str) if (iface_initialized == 0) { - iface_list.used = 0; + iface_list_used = 0; iface_initialized = 1; } @@ -1608,7 +1834,7 @@ static int sh_portchk_add_interface (const char * str) if (0 == sh_ipvx_aton(buf, &saddr)) return -1; - if (iface_list.used == SH_IFACE_MAX) + if (iface_list_used == SH_IFACE_MAX) return -1; sh_ipvx_ntoa(ipbuf, sizeof(ipbuf), &saddr); @@ -1618,8 +1844,9 @@ static int sh_portchk_add_interface (const char * str) errbuf, _("sh_portchk_add_interface")); SH_MUTEX_UNLOCK(mutex_thread_nolog); - memcpy (&(iface_list.iface[iface_list.used]), &(saddr), sizeof(saddr)); - ++iface_list.used; + memcpy (&(iface_list[iface_list_used].iface), &(saddr), sizeof(saddr)); + iface_list[iface_list_used].type = type; + ++iface_list_used; } } while (*str); @@ -1627,6 +1854,230 @@ static int sh_portchk_add_interface (const char * str) return 0; } +static int sh_portchk_add_interface (const char * str) +{ + return sh_portchk_add_interface_int (str, SH_IFACE_ADDR); +} + +#if defined(HAVE_IFADDRS_H) +/* + * subroutines to add a device + */ +void * sh_dummy_1651_ifa = NULL; /* fix clobbered by.. warning */ + +static int portchk_add_device_int (const char * buf) +{ + struct ifaddrs *ifaddr, *ifa; + int family; +#ifndef NI_MAXHOST +#define NI_MAXHOST 1025 +#endif + char host[NI_MAXHOST]; + + sh_dummy_1651_ifa = (void*) &ifa; + + if (getifaddrs(&ifaddr) == -1) + { + volatile int nerr = errno; + char errbuf[SH_ERRBUF_SIZE]; + sh_error_message(errno, errbuf, sizeof(errbuf)); + SH_MUTEX_LOCK(mutex_thread_nolog); + sh_error_handle((-1), FIL__, __LINE__, nerr, MSG_E_SUBGEN, + errbuf, _("getifaddrs")); + SH_MUTEX_UNLOCK(mutex_thread_nolog); + return -1; + } + + for ( ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) + { + if (ifa->ifa_addr == NULL) + continue; + + if (strcmp(ifa->ifa_name, buf) == 0) + { + volatile int s = 0; + family = ifa->ifa_addr->sa_family; + + if (family == AF_INET) + { + s = getnameinfo( ifa->ifa_addr, sizeof(struct sockaddr_in), + host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST ); + + if (s == 0) + { + if (sh_portchk_add_interface_int(host, SH_IFACE_DEV) < 0) + { + freeifaddrs(ifaddr); + return -1; + } + } + } + +#if defined(USE_IPVX) + if (family == AF_INET6) + { + s = getnameinfo( ifa->ifa_addr, sizeof(struct sockaddr_in6), + host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST ); + + if (s == 0) + { + if (sh_portchk_add_interface_int(host, SH_IFACE_DEV) < 0) + { + freeifaddrs(ifaddr); + return -1; + } + } + } +#endif + + if (s != 0) + { + char errbuf[SH_ERRBUF_SIZE]; + sl_strlcpy(errbuf, buf, sizeof(errbuf)); + sl_strlcat(errbuf, ": ", sizeof(errbuf)); + sl_strlcat(errbuf, gai_strerror(s), sizeof(errbuf)); + SH_MUTEX_LOCK(mutex_thread_nolog); + sh_error_handle((-1), FIL__, __LINE__, s, MSG_E_SUBGEN, + errbuf, _("getnameinfo")); + SH_MUTEX_UNLOCK(mutex_thread_nolog); + } + + } + } + + freeifaddrs(ifaddr); + return 0; +} + +struct added_dev { + char dev[64]; + struct added_dev * next; +}; + +static struct added_dev * dev_list = NULL; + +static void dev_list_add (char * buf) +{ + struct added_dev * new = SH_ALLOC(sizeof(struct added_dev)); + sl_strlcpy(new->dev, buf, 64); + new->next = dev_list; + dev_list = new; + return; +} + +static void dev_list_kill () +{ + struct added_dev * old; + struct added_dev * new = dev_list; + dev_list = NULL; + + while (new) + { + old = new; + new = new->next; + SH_FREE(old); + } + return; +} + +static int sh_portchk_add_device (const char * str) +{ + char buf[64]; + + do { + + while (*str == ',' || *str == ' ' || *str == '\t') ++str; + + if (*str) + { + unsigned int i = 0; + while (*str && i < (sizeof(buf)-1) && + *str != ',' && *str != ' ' && *str != '\t') { + buf[i] = *str; ++str; ++i; + } + buf[i] = '\0'; + + if (portchk_add_device_int (buf) < 0) + return -1; + + dev_list_add(buf); + } + } while (*str); + + return 0; +} + +static int iface_comp (const void *a, const void *b) +{ + const struct portchk_interfaces * aa = (const struct portchk_interfaces *) a; + const struct portchk_interfaces * bb = (const struct portchk_interfaces *) b; + return (aa->type - bb->type); +} + +static void iface_qsort() +{ + qsort(&iface_list[0], iface_list_used, sizeof(struct portchk_interfaces), + iface_comp); + return; +} + +static void recheck_devices() +{ + if (dev_list) + { + struct added_dev * dev = dev_list; + int i, j; + + if (portchk_debug) + { + for (j = 0; j < iface_list_used; ++j) + { + char buf[SH_IP_BUF]; + struct portchk_interfaces * aa = &(iface_list[j]); + sh_ipvx_ntoa(buf, sizeof(buf), &(aa->iface)); + fprintf(stderr, _("presort: iface[%d] type(%d) %s\n"), j, iface_list[j].type, buf); + } + } + + iface_qsort(); + + if (portchk_debug) + { + for (j = 0; j < iface_list_used; ++j) + { + char buf[SH_IP_BUF]; + struct portchk_interfaces * aa = &(iface_list[j]); + sh_ipvx_ntoa(buf, sizeof(buf), &(aa->iface)); + fprintf(stderr, _("postsor: iface[%d] type(%d) %s\n"), j, iface_list[j].type, buf); + } + } + + i = 0; + for (j = 0; j < iface_list_used; ++j) + if (iface_list[j].type == SH_IFACE_DEV) ++i; + iface_list_used -= i; + + if (portchk_debug) + { + for (j = 0; j < iface_list_used; ++j) + { + char buf[SH_IP_BUF]; + struct portchk_interfaces * aa = &(iface_list[j]); + sh_ipvx_ntoa(buf, sizeof(buf), &(aa->iface)); + fprintf(stderr, _("postdel: iface[%d] type(%d) %s\n"), j, iface_list[j].type, buf); + } + } + + while (dev) + { + portchk_add_device_int (dev->dev); + dev = dev->next; + } + } + return; +} +#endif + /* verify whether port/interface is blacklisted (do not check) */ static int sh_portchk_is_blacklisted(int port, struct sh_sockaddr * saddr, @@ -1641,14 +2092,8 @@ static int sh_portchk_is_blacklisted(int port, struct sh_sockaddr * saddr, while (head) { - if (head->port == port) - { - if (sh_ipvx_isany(head->paddr) || - 0 == sh_ipvx_cmp(head->paddr, saddr)) - return 1; - else - return 0; - } + if (head->port == port && ( sh_ipvx_isany(head->paddr) || 0 == sh_ipvx_cmp(head->paddr, saddr) )) + return 1; head = head->next; } return 0; @@ -1694,8 +2139,75 @@ static int sh_portchk_blacklist(int port, struct sh_sockaddr * saddr, int proto) } return 0; } + + +/* verify whether port/interface is transient (used as source port + *hence no check required) + */ +static int sh_portchk_is_transient(int port, struct sh_sockaddr * saddr, + int proto) +{ + struct sh_port * head; - + if (proto == IPPROTO_TCP) + head = transient_tcp; + else + head = transient_udp; + + while (head) + { + if (head->port == port && ( sh_ipvx_isany(head->paddr) || 0 == sh_ipvx_cmp(head->paddr, saddr) )) + return 1; + head = head->next; + } + return 0; +} + + +static int sh_portchk_transient(int port, struct sh_sockaddr * saddr, int proto) +{ + struct sh_port * transient; + struct sh_port * head; + + if (sh_portchk_transients == S_FALSE) + return 0; + + if (proto == IPPROTO_TCP) + head = transient_tcp; + else + head = transient_udp; + + transient = head; + + while (transient) + { + if (transient->port == port && + 0 == sh_ipvx_cmp(head->paddr, saddr)) + return -1; + transient = transient->next; + } + + transient = SH_ALLOC (sizeof(struct sh_port)); + transient->paddr = SH_ALLOC (sizeof(struct sh_sockaddr)); + transient->port = port; + memcpy(transient->paddr, saddr, sizeof(struct sh_sockaddr)); + transient->next = head; + + if (proto == IPPROTO_TCP) + transient_tcp = transient; + else + transient_udp = transient; + + if (portchk_debug) + { + int checkit = sh_portchk_is_transient(port, saddr, proto); + fprintf(stderr, _("port transient: %d %s\n"), port, + (checkit == 1) ? _("ok") : _("fail")); + } + return 0; +} + + /* Subroutine to add a required or optional port/service */ static int sh_portchk_add_required_port_generic (char * service, @@ -1717,9 +2229,9 @@ static int sh_portchk_add_required_port_generic (char * service, p = strchr(buf, '/'); if (!p) return -1; - if (0 == strcmp(p, _("/tcp"))) + if (0 == strcasecmp(p, _("/tcp"))) proto = IPPROTO_TCP; - else if (0 == strcmp(p, _("/udp"))) + else if (0 == strcasecmp(p, _("/udp"))) proto = IPPROTO_UDP; else return -1; @@ -1927,6 +2439,11 @@ int sh_portchk_check () SH_MUTEX_UNLOCK(mutex_thread_nolog); sh_portchk_reset_lists(); + +#if defined(HAVE_IFADDRS_H) + recheck_devices(); +#endif + if ((0 != geteuid()) && (min_port < 1024)) { min_port = 1024; diff --git a/src/sh_prelude.c b/src/sh_prelude.c index 74fda3a..d00e9b4 100644 --- a/src/sh_prelude.c +++ b/src/sh_prelude.c @@ -37,6 +37,7 @@ #include <stdio.h> #include <string.h> +#include <ctype.h> #include <sys/types.h> #if TIME_WITH_SYS_TIME @@ -809,8 +810,6 @@ static int get_service_info(char *msg, idmef_alert_t *alert) port = strtol(ptr, &end, 0); if ( *ptr && *end == '\0' && port >= 0 && port < 65536) { - char * tmpw; - if ( ! source ) { ret = idmef_alert_new_source(alert, &source, IDMEF_LIST_APPEND); if ( ret < 0 ) { diff --git a/src/sh_processcheck.c b/src/sh_processcheck.c index f5601c9..a5786f0 100644 --- a/src/sh_processcheck.c +++ b/src/sh_processcheck.c @@ -751,7 +751,7 @@ static short sh_processes_check (pid_t pid, short res) #endif #endif -#if !defined(sun) && !defined(__sun) && !defined(__sun__) +#if !defined(sun) && !defined(__sun) && !defined(__sun__) && !defined(__OpenBSD__) && !defined(__APPLE__) #ifdef _POSIX_PRIORITY_SCHEDULING struct sched_param p; #endif @@ -785,8 +785,9 @@ static short sh_processes_check (pid_t pid, short res) #endif /* sched_getparam() is broken on solaris 10, may segfault in librt + * also not on MacOS */ -#if !defined(sun) && !defined(__sun) && !defined(__sun__) +#if !defined(sun) && !defined(__sun) && !defined(__sun__) && !defined(__OpenBSD__) && !defined(__APPLE__) #ifdef _POSIX_PRIORITY_SCHEDULING if (0 == sched_getparam (pid, &p)) { diff --git a/src/sh_readconf.c b/src/sh_readconf.c index 892be10..a37bc4e 100644 --- a/src/sh_readconf.c +++ b/src/sh_readconf.c @@ -33,7 +33,7 @@ #include "sh_unix.h" #include "sh_files.h" #include "sh_xfer.h" -#include "sh_gpg.h" +#include "sh_sig.h" #include "sh_hash.h" #include "sh_dbIO.h" #include "sh_ignore.h" @@ -351,8 +351,8 @@ int sh_readconf_read (void) #if defined(SH_STEALTH) && !defined(SH_STEALTH_MICRO) SL_TICKET fdTmp = -1; #endif -#if defined(WITH_GPG) || defined(WITH_PGP) - SL_TICKET fdGpg = -1; +#if defined(WITH_SIG) + SL_TICKET fdSIG = -1; #endif char * tmp; @@ -368,7 +368,7 @@ int sh_readconf_read (void) int local_file = 1; char local_flag = 'R'; -#if defined(WITH_GPG) || defined(WITH_PGP) +#if defined(WITH_SIG) int signed_content = S_FALSE; int true_content = S_FALSE; #endif @@ -469,8 +469,8 @@ int sh_readconf_read (void) { sl_write_line(fdTmp, line_in, sl_strlen(line_in)); } -#if defined(WITH_GPG) || defined(WITH_PGP) - if (0 == sl_strncmp(line_in, _("-----END PGP SIGNATURE-----"), 25)) +#if defined(WITH_SIG) + if (S_TRUE == sh_sig_data_end(line_in)) break; #else if (0 == sl_strncmp(line_in, _("[EOF]"), 5)) @@ -484,18 +484,18 @@ int sh_readconf_read (void) sl_rewind (fd); #endif -#if defined(WITH_GPG) || defined(WITH_PGP) +#if defined(WITH_SIG) /* extract the data and copy to temporary file */ - fdGpg = sh_gpg_extract_signed(fd); + fdSIG = sh_sig_extract_signed(fd); sl_close(fd); - fd = fdGpg; + fd = fdSIG; /* Validate signature of open file. */ - if (0 != sh_gpg_check_sign (fd, SIG_CONF)) + if (0 != sh_sig_check_signature (fd, SIG_CONF)) { SH_FREE(line_in); sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_EXIT_ABORT1, sh.prg_name); @@ -519,26 +519,19 @@ int sh_readconf_read (void) /* Sun May 27 18:40:05 CEST 2001 */ -#if defined(WITH_GPG) || defined(WITH_PGP) +#if defined(WITH_SIG) if (signed_content == S_FALSE) { - if (0 == sl_strcmp(line, _("-----BEGIN PGP SIGNED MESSAGE-----"))) + if (S_TRUE == sh_sig_msg_start(line)) signed_content = S_TRUE; else continue; } - else if (true_content == S_FALSE) - { - if (line[0] == '\n') - true_content = S_TRUE; - else - continue; - } - else if (signed_content == S_TRUE) + else /* if (signed_content == S_TRUE) */ { - if (0 == sl_strcmp(line, _("-----BEGIN PGP SIGNATURE-----"))) + if (S_TRUE == sh_sig_msg_end(line)) break; - else if (0 == sl_strcmp(line, _("-----BEGIN PGP SIGNED MESSAGE-----"))) + else if (S_TRUE == sh_sig_msg_start(line)) { sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, _("second signed message in file"), @@ -551,6 +544,14 @@ int sh_readconf_read (void) aud_exit (FIL__, __LINE__,EXIT_FAILURE); } } + + if (true_content == S_FALSE) /* continue if in header */ + { + if (S_TRUE == sh_sig_msg_startdata(line)) + true_content = S_TRUE; + else + continue; + } #endif /* Skip leading white space. @@ -1017,6 +1018,10 @@ cfg_options ext_table[] = { { N_("useaclcheck"), SH_SECTION_MISC, SH_SECTION_NONE, sh_unix_setcheckacl }, #endif +#if !defined(SH_COMPILE_STATIC) && defined(__linux__) && defined(HAVE_AUPARSE_H) && defined(HAVE_AUPARSE_LIB) + { N_("setauditdflags"), SH_SECTION_MISC, SH_SECTION_NONE, + sh_audit_set_flags }, +#endif { N_("loosedircheck"), SH_SECTION_MISC, SH_SECTION_NONE, sh_hash_loosedircheck }, { N_("addokchars"), SH_SECTION_MISC, SH_SECTION_NONE, @@ -1142,6 +1147,8 @@ cfg_options ext_table[] = { sh_xfer_set_port }, { N_("setserverinterface"), SH_SECTION_SRV, SH_SECTION_MISC, sh_xfer_set_interface }, + { N_("alias"), SH_SECTION_CLIENTS, SH_SECTION_NONE, + sh_xfer_register_alias }, { N_("client"), SH_SECTION_CLIENTS, SH_SECTION_NONE, sh_xfer_register_client }, #endif diff --git a/src/sh_registry.c b/src/sh_registry.c index 16502a6..f940cd2 100644 --- a/src/sh_registry.c +++ b/src/sh_registry.c @@ -349,7 +349,7 @@ static void report_missing_entry(const char * path) char timestr[32]; struct store2db save; - memset(&save, '\0', sizeof(struct store2db)); + memset(&save, 0, sizeof(struct store2db)); sh_hash_db2pop (path, &save); (void) sh_unix_gmttime (save.val1, timestr, sizeof(timestr)); @@ -681,7 +681,7 @@ int QueryKey(HKEY hKey, char * path, size_t pathlen, int isSingle) { struct store2db save; - memset(&save, '\0', sizeof(struct store2db)); + memset(&save, 0, sizeof(struct store2db)); if (tPath) { @@ -773,7 +773,7 @@ int QueryKey(HKEY hKey, char * path, size_t pathlen, int isSingle) { struct store2db save; - memset(&save, '\0', sizeof(struct store2db)); + memset(&save, 0, sizeof(struct store2db)); save.val0 = totalSize; save.val1 = fTime; @@ -840,6 +840,9 @@ int CheckThisSubkey (HKEY key, char * subkey, char * path, int isSingle, char * newpath; size_t len; int retval = -1; + + if (!subkey) + return 0; len = strlen(path) + 1 + strlen(subkey) + 1; newpath = SH_ALLOC(len); @@ -933,7 +936,7 @@ int CheckThisSubkey (HKEY key, char * subkey, char * path, int isSingle, int check_key (char * key, int isSingle) { HKEY topKey; - char * subkey; + char * subkey = NULL; char path[20] = ""; int pos = 0; @@ -973,7 +976,7 @@ int check_key (char * key, int isSingle) } else { - + /* We bail out here if the topKey is undefined */ char * tmp = sh_util_safe_name_keepspace(key); size_t tlen = sl_strlen(tmp); @@ -1002,6 +1005,8 @@ int check_key (char * key, int isSingle) } *************************/ + /* Returns 0 if !subkey */ + /* cppcheck-suppress uninitvar */ return CheckThisSubkey (topKey, subkey, path, isSingle, 0); } diff --git a/src/sh_restrict.c b/src/sh_restrict.c index 4e255e3..7409751 100644 --- a/src/sh_restrict.c +++ b/src/sh_restrict.c @@ -603,7 +603,7 @@ void Test_restrict (CuTest *tc) { CuAssertIntEquals(tc,0,res); CuAssertPtrNotNull(tc, sh_restrict_list); -#if !defined(HOST_IS_CYGWIN) +#if !defined(HOST_IS_CYGWIN) && !defined(HOST_IS_DARWIN) res = sh_restrict_this("/bin/sh", 1000, 0755, fd); CuAssertIntEquals(tc,1,res); #endif diff --git a/src/sh_sem.c b/src/sh_sem.c index 3de83b4..66c21db 100644 --- a/src/sh_sem.c +++ b/src/sh_sem.c @@ -43,11 +43,12 @@ typedef enum { exit_err = 3 } sh_estat; -#if 0 + /* FreeBSD 6.1 defines this in <sys/sem.h> too... */ #if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) /* union semun is defined by including <sys/sem.h> */ #else +#if !defined(HAVE_UNION_SEMUN) /* according to X/OPEN we have to define it ourselves */ union semun { int val; @@ -57,6 +58,7 @@ union semun { #endif #endif + #define SH_SEMVMX 32767 static int get_semaphore (void) @@ -74,8 +76,12 @@ static int get_semaphore (void) static void sem_purge(int sem_id) { + union semun tmp; + + tmp.val = 0; + if (sem_id != -1) - semctl(sem_id, 0, IPC_RMID, (int)0); + semctl(sem_id, 0, IPC_RMID, tmp); return; } @@ -102,6 +108,7 @@ static int init_semaphore (int nsems) mode_t mask; int semid; int errnum; + union semun tmp; key_t key = ftok(DEFAULT_DATAROOT, '#'); if (key < 0) @@ -111,11 +118,13 @@ static int init_semaphore (int nsems) semid = semget (key, nsems, IPC_CREAT | IPC_EXCL | 0660); errnum = errno; umask(mask); + + tmp.val = 1; if (semid < 0) return report_err(errnum, FIL__, __LINE__, _("semget")); for (i=0; i<nsems; ++i) - if (semctl (semid, i, SETVAL, (int) 1) == -1) + if (semctl (semid, i, SETVAL, tmp) == -1) return report_err(errnum, FIL__, __LINE__, _("semclt")); return semid; } @@ -123,18 +132,24 @@ static int init_semaphore (int nsems) static int sem_set(int semid, int sem_no, int val) { + union semun tmp; + + tmp.val = val; + if (semid < 0) return -1; - if (semctl (semid, sem_no, SETVAL, val) == -1) + if (semctl (semid, sem_no, SETVAL, tmp) == -1) return -1; return 0; } static int sem_get(int semid, int sem_no) { + union semun tmp; if (semid < 0) return -1; - return semctl (semid, sem_no, GETVAL, (int) 0); + tmp.val = 0; + return semctl (semid, sem_no, GETVAL, tmp); } diff --git a/src/sh_sig.c b/src/sh_sig.c new file mode 100644 index 0000000..ea8c3cb --- /dev/null +++ b/src/sh_sig.c @@ -0,0 +1,1789 @@ +/* SAMHAIN file system integrity testing */ +/* Copyright (C) 1999, 2000 Rainer Wichmann */ +/* */ +/* This program is free software; you can redistribute it */ +/* and/or modify */ +/* it under the terms of the GNU General Public License as */ +/* published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config_xor.h" + +#include <stdio.h> +#include <stdlib.h> + + +#if defined(WITH_SIG) + +#include <unistd.h> +#include <fcntl.h> +#include <signal.h> +#if defined(SH_WITH_SERVER) +#include <pwd.h> +#endif +#include <sys/stat.h> +#include <sys/types.h> +#include <errno.h> +#include <sys/wait.h> + +#include <string.h> +#ifdef HAVE_MEMORY_H +#include <memory.h> +#endif + + +#if !defined(O_NONBLOCK) +#if defined(O_NDELAY) +#define O_NONBLOCK O_NDELAY +#else +#define O_NONBLOCK 0 +#endif +#endif + + +#include "samhain.h" +#include "sh_utils.h" +#include "sh_error.h" +#include "sh_tiger.h" +#if defined(SH_WITH_SERVER) +#define SH_NEED_PWD_GRP 1 +#include "sh_static.h" +#endif +#include "sh_sig.h" + +int get_the_fd(SL_TICKET file_1); + +#if defined(WITH_GPG) +static struct { + char conf_id[SH_MINIBUF+1]; + char conf_fp[SH_MINIBUF+1]; + char data_id[SH_MINIBUF+1]; + char data_fp[SH_MINIBUF+1]; +} gp; +#endif + +typedef struct { + pid_t pid; + FILE * pipe; +} sh_gpg_popen_t; + +#define SH_SIG_OK 0 +#define SH_SIG_BAD 1 +#define SH_SIG_BADSIGN 2 + +/* replace #if 0 by #if 1 and set an appropriate path in front of '/pdbg.' + * for debugging + */ +#if 0 +#define PDGBFILE "/pdbg." +#endif + +#if defined(PDGBFILE) +FILE * pdbg; +FILE * pdbgc; +#define PDBG_OPEN pdbg = fopen(PDGBFILE"main", "a") +#define PDBG_CLOSE sl_fclose (FIL__, __LINE__, pdbg) +#define PDBG(arg) fprintf(pdbg, "PDBG: step %d\n", arg); fflush(pdbg) +#define PDBG_D(arg) fprintf(pdbg, "PDBG: %d\n", arg); fflush(pdbg) +#define PDBG_S(arg) fprintf(pdbg, "PDBG: %s\n", arg); fflush(pdbg) + +#define PDBGC_OPEN pdbgc = fopen(PDGBFILE"child", "a") +#define PDBGC_CLOSE sl_fclose (FIL__, __LINE__, pdbgc) +#define PDBGC(arg) fprintf(pdbgc, "PDBG: step %d\n", arg); fflush(pdbgc) +#define PDBGC_D(arg) fprintf(pdbgc, "PDBG: %d\n", arg); fflush(pdbgc) +#define PDBGC_S(arg) fprintf(pdbgc, "PDBG: %s\n", arg); fflush(pdbgc) +#else +#define PDBG_OPEN +#define PDBG_CLOSE +#define PDBG(arg) +#define PDBG_D(arg) +#define PDBG_S(arg) +#define PDBGC_OPEN +#define PDBGC_CLOSE +#define PDBGC(arg) +#define PDBGC_D(arg) +#define PDBGC_S(arg) +#endif + +#undef FIL__ +#define FIL__ _("sh_sig.c") + +#if defined(SIG_HASH) || defined(SIG_KEY_HASH) + +typedef enum { SIG_HASH_REPORT, SIG_HASH_REPORTFULL, SIG_HASH_OTHER } checksum_flag; + +static int sh_sig_checksum (SL_TICKET checkfd, checksum_flag flag, const char * expected_in, const char * path) +{ + char * test_sig; + char * expected = NULL; + char * test_ptr1 = NULL; + char * test_ptr2 = NULL; + char wstrip1[128]; + char wstrip2[128]; + int i, k; +#include "sh_sig_chksum.h" + + SL_ENTER(_("sh_sig_checksum")); + + + if (flag == SIG_HASH_OTHER) + expected = sh_util_strdup(expected_in); + + if (flag == SIG_HASH_OTHER) + test_sig = sh_tiger_hash_gpg (path, checkfd, TIGER_NOLIM); + else + test_sig = sh_tiger_hash_gpg (DEFAULT_SIG_PATH, checkfd, TIGER_NOLIM); + + test_ptr1 = (flag == SIG_HASH_OTHER) ? strchr(expected, ':') : strchr(SIG_HASH, ':'); + if (test_ptr1 != NULL) + test_ptr1 += 2; + else + test_ptr1 = (flag == SIG_HASH_OTHER) ? expected : SIG_HASH; + + if (test_sig != NULL) + test_ptr2 = strchr(test_sig, ':'); + if (test_ptr2 != NULL) + test_ptr2 += 2; + else + test_ptr2 = test_sig; + + /* Tue Jun 24 23:11:54 CEST 2003 (1.7.9) -- strip whitespace + */ + k = 0; + for (i = 0; i < 127; ++i) + { + if (test_ptr1[i] == '\0') + break; + if (test_ptr1[i] != ' ') + { + wstrip1[k] = test_ptr1[i]; + ++k; + } + } + wstrip1[k] = '\0'; + + if (flag != SIG_HASH_OTHER) + { + for(i = 0; i < KEY_LEN; ++i) + { + if (sigchk[i] != wstrip1[i]) + { + sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0, MSG_E_GPG_CHK, + sigchk, wstrip1); + break; + } + } + } + + k = 0; + if (test_ptr2) + { + for (i = 0; i < 127; ++i) + { + if (test_ptr2[i] == '\0') + break; + if (test_ptr2[i] != ' ') + { + wstrip2[k] = test_ptr2[i]; + ++k; + } + } + } + wstrip2[k] = '\0'; + + if (0 != sl_strncmp(wstrip1, wstrip2, 127)) + { + TPT(((0), FIL__, __LINE__, _("msg=<sig checksum: %s>\n"), test_sig)); + TPT(((0), FIL__, __LINE__, _("msg=<compiled in : %s>\n"), (flag == SIG_HASH_OTHER) ? expected : SIG_HASH)); + TPT(((0), FIL__, __LINE__, _("msg=<wstrip1 : %s>\n"), wstrip1)); + TPT(((0), FIL__, __LINE__, _("msg=<wstrip2 : %s>\n"), wstrip2)); + if (flag == SIG_HASH_REPORTFULL) + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_GPG, + SIG_HASH, test_sig); + if (flag == SIG_HASH_OTHER) + dlog(1, FIL__, __LINE__, _("The compiled-in checksum of the public key %s\n(%s)\ndoes not match the actual checksum\n(%s).\nYou need to recompile with the correct checksum."), path, wstrip1, wstrip2); + else + dlog(1, FIL__, __LINE__, _("The compiled-in checksum of the signature checking binary %s\n(%s)\ndoes not match the actual checksum\n(%s).\nYou need to recompile with the correct checksum."), DEFAULT_SIG_PATH, wstrip1, wstrip2); + SH_FREE(test_sig); + if (expected) + SH_FREE(expected); + SL_RETURN((-1), _("sh_sig_checksum")); + } + SH_FREE(test_sig); + if (expected) + SH_FREE(expected); + SL_RETURN( (0), _("sh_sig_checksum")); +} +#endif + +struct startup_info { + long line; + char * program; + long uid; + char * path; + char * key_uid; + char * key_id; +}; + +static struct startup_info startInfo = { 0, NULL, 0, NULL, NULL, NULL }; + +static void sh_sig_fill_startup (long line, char * program, long uid, char * path, + char * key_uid, char * key_id) +{ + startInfo.line = line; + startInfo.program = sh_util_strdup(program); + startInfo.uid = uid; + startInfo.path = sh_util_strdup(path); + if (key_uid) + startInfo.key_uid = sh_util_strdup(key_uid); + else + startInfo.key_uid = sh_util_strdup(_("(not given)")); + if (key_id) + startInfo.key_id = sh_util_strdup(key_id); + else + startInfo.key_id = sh_util_strdup(_("(not given)")); + return; +} + +typedef enum { SIG_DATASIG, SIG_DATAONLY } extractlevel; + + +static FILE * sh_sig_popen (char *const argv[], sh_gpg_popen_t *source, int fd); + + +static FILE * sh_sig_popen (char *const arg[], sh_gpg_popen_t *source, int fd) +{ + size_t len; + extern int flag_err_debug; + int pipedes[2]; + FILE * outf = NULL; + char * envp[2]; + +#if defined(HAVE_SIG_CHECKSUM) + SL_TICKET checkfd = -1; + int myrand; + int i; +#if defined(__linux__) + int get_the_fd(SL_TICKET); + char pname[128]; + int pfd; + int val_return; +#endif +#endif + + SL_ENTER(_("sh_sig_popen")); + + /* use homedir of effective user + */ + len = sl_strlen(sh.effective.home) + 6; + envp[0] = calloc(1, len); /* free() ok */ + if (envp[0] != NULL) + sl_snprintf (envp[0], len, _("HOME=%s"), sh.effective.home); + envp[1] = NULL; + + /* Create the pipe + */ + if (aud_pipe(FIL__, __LINE__, pipedes) < 0) + { + if (envp[0] != NULL) + free(envp[0]); + SL_RETURN( (NULL), _("sh_gpg_popen")); + } + + fflush (NULL); + + source->pid = aud_fork(FIL__, __LINE__); + + /* Failure + */ + if (source->pid == (pid_t) - 1) + { + sl_close_fd(FIL__, __LINE__, pipedes[0]); + sl_close_fd(FIL__, __LINE__, pipedes[1]); + if (envp[0] != NULL) + free(envp[0]); + SL_RETURN( (NULL), _("sh_sig_popen")); + } + + if (source->pid == (pid_t) 0) + { + + /* child - make read side of the pipe stdout + */ + if (retry_aud_dup2(FIL__, __LINE__, + pipedes[STDOUT_FILENO], STDOUT_FILENO) < 0) + { + TPT(((0), FIL__, __LINE__, _("msg=<dup2 on pipe failed>\n"))); + dlog(1, FIL__, __LINE__, _("Internal error: dup2 failed\n")); + aud__exit(FIL__, __LINE__, EXIT_FAILURE); + } + + /* close the pipe descriptors + */ + sl_close_fd (FIL__, __LINE__, pipedes[STDIN_FILENO]); + sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]); + + if (retry_aud_dup2(FIL__, __LINE__, fd, STDIN_FILENO) < 0) + { + TPT(((0), FIL__, __LINE__, _("msg=<dup2 on fd failed>\n"))); + dlog(1, FIL__, __LINE__, _("Internal error: dup2 failed\n")); + aud__exit(FIL__, __LINE__, EXIT_FAILURE); + } + + /* don't leak file descriptors + */ + sh_unix_closeall (3, -1, S_TRUE); /* in child process */ + + if (flag_err_debug != S_TRUE) + { + if (NULL == freopen(_("/dev/null"), "r+", stderr)) + { + dlog(1, FIL__, __LINE__, _("Internal error: freopen failed\n")); + aud__exit(FIL__, __LINE__, EXIT_FAILURE); + } + } + + + /* We should become privileged if SUID, + * to be able to read the keyring. + * We have checked that gpg is OK, + * AND that only a trusted user could overwrite + * gpg. + */ + memset (skey, 0, sizeof(sh_key_t)); + aud_setuid(FIL__, __LINE__, geteuid()); + + PDBGC_OPEN; + PDBGC_D((int)getuid()); + PDBGC_D((int)geteuid()); + + { + int i = 0; + while (arg[i] != NULL) + { + PDBGC_S(arg[i]); + ++i; + } + } + PDBGC_CLOSE; + + /* exec the program */ + +#if defined(__linux__) && defined(HAVE_SIG_CHECKSUM) + /* + * -- emulate an fexecve with checksum testing + */ + checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_SIG_PATH, SL_NOPRIV); + + if (0 != sh_sig_checksum(checkfd, SIG_HASH_REPORT, NULL, NULL)) + { + sl_close(checkfd); + aud__exit(FIL__, __LINE__, EXIT_FAILURE); + } + + pfd = get_the_fd(checkfd); + do { + val_return = dup (pfd); + } while (val_return < 0 && errno == EINTR); + pfd = val_return; + sl_close(checkfd); + /* checkfd = -1; *//* never read */ + + sl_snprintf(pname, sizeof(pname), _("/proc/self/fd/%d"), pfd); + if (0 == access(pname, R_OK|X_OK)) /* flawfinder: ignore */ + + { + fcntl (pfd, F_SETFD, FD_CLOEXEC); + retry_aud_execve (FIL__, __LINE__, pname, arg, envp); + + dlog(1, FIL__, __LINE__, _("Unexpected error: execve %s failed\n"), + pname); + /* failed + */ + aud__exit(FIL__, __LINE__, EXIT_FAILURE); + } + + /* procfs not working, go ahead + */ +#endif + +#if defined(HAVE_SIG_CHECKSUM) + /* This is an incredibly ugly kludge to prevent an attacker + * from knowing when it is safe to slip in a fake executable + * between the integrity check and the execve + */ + myrand = (int) taus_get (); + + myrand = (myrand < 0) ? (-myrand) : myrand; + myrand = (myrand % 32) + 2; + + for (i = 0; i < myrand; ++i) + { + checkfd = sl_open_fastread(FIL__, __LINE__, + DEFAULT_SIG_PATH, SL_NOPRIV); + + if (0 != sh_sig_checksum(checkfd, SIG_HASH_REPORT, NULL, NULL)) { + aud__exit(FIL__, __LINE__, EXIT_FAILURE); + } + sl_close(checkfd); + } +#endif + + retry_aud_execve (FIL__, __LINE__, DEFAULT_SIG_PATH, arg, envp); + dlog(1, FIL__, __LINE__, _("Unexpected error: execve %s failed\n"), + DEFAULT_SIG_PATH); + + /* failed + */ + TPT(((0), FIL__, __LINE__, _("msg=<execve failed>\n"))); + dlog(1, FIL__, __LINE__, _("Unexpected error: execve failed\n")); + aud__exit(FIL__, __LINE__, EXIT_FAILURE); + } + + /* parent + */ + + if (envp[0] != NULL) + free(envp[0]); + + sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]); + retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC); + retry_fcntl (FIL__, __LINE__, pipedes[STDIN_FILENO], F_SETFL, O_NONBLOCK); + + outf = fdopen (pipedes[STDIN_FILENO], "r"); + + if (outf == NULL) + { + aud_kill (FIL__, __LINE__, source->pid, SIGKILL); + sl_close_fd (FIL__, __LINE__, pipedes[STDOUT_FILENO]); + waitpid (source->pid, NULL, 0); + source->pid = 0; + SL_RETURN( (NULL), _("sh_sig_popen")); + } + + SL_RETURN( (outf), _("sh_sig_popen")); +} + + +static int sh_sig_pclose (sh_gpg_popen_t *source) +{ + int status = 0; + + SL_ENTER(_("sh_sig_pclose")); + + status = sl_fclose(FIL__, __LINE__, source->pipe); + if (status) + SL_RETURN( (-1), _("sh_sig_pclose")); + + if (waitpid(source->pid, NULL, 0) != source->pid) + status = -1; + + source->pipe = NULL; + source->pid = 0; + SL_RETURN( (status), _("sh_sig_pclose")); +} + +/* This is signify specific stuff + */ +#if defined(WITH_SIGNIFY) + +#include <ctype.h> + +static +int sh_signify_comp_comm(const char * line, size_t * commlen) +{ + /* check for a valid comment line: not exceeding 1023 chars and + * starting with 'untrusted comment: ' */ + static char cmp[SH_MINIBUF]; + static size_t cmp_len = 0; + + size_t len = sl_strlen(line); + + if (cmp_len == 0) { + sl_strlcpy(cmp, _("untrusted comment: "), sizeof(cmp)); + cmp_len = strlen(cmp); + } + + if (line[len-1] == '\n') { + /* signify will replace the '\n' with '\0', so 1024 -> 1023, which fits */ + if (len > 1024) return S_FALSE; + else *commlen = len; + } else { + if (len > 1023) return S_FALSE; + else *commlen = (len+1); + } + + if (len >= cmp_len && 0 == strncmp(cmp, line, cmp_len)) + return S_TRUE; + return S_FALSE; +} + +static const char bto64_0[] = N_("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); +static char bto64[65] = { '\0' }; + +static +int sh_signify_comp_sig(const char * line, size_t commlen) +{ + char cmp[128]; + char out[128]; + size_t len = sl_strlen(line); + size_t i, j = 0; + int padf = 0; + + if (bto64[0] == '\0') + memcpy(bto64, _(bto64_0), 65); + + if (line[len-1] == '\n') { + if ((len+commlen) > 2047) return S_FALSE; + } else { + if ((len+commlen) > 2046) return S_FALSE; + } + + for (i = 0; i < len; ++i) + { + if (isspace(line[i])) { + /* signify will skip arbitrary space, using isspace() */ + continue; + } + if (line[i] == '=') { + if (padf > 1) /* more than two padding '=' */ + return S_FALSE; + else + ++padf; + } else if (!strchr(bto64, line[i]) || (line[i] == '=' && padf > 0)) { + return S_FALSE; + } + if (j < sizeof(cmp)) { + cmp[j] = line[i]; ++j; + } + } + + /* signature is 'Ed' + 8 byte random + 64 bytes = 74 bytes + * => 1 pad byte => 75 bytes => 100 b64 bytes */ + if (j != 100 || padf != 1) + return S_FALSE; + + cmp[j] = '\0'; /* j == 100 */ + sh_util_base64_dec((unsigned char *) out, (unsigned char *) cmp, j); + if(out[0] == 'E' && out[1] == 'd') + return S_TRUE; + + return S_FALSE; +} +static +int sh_signify_msg_start(const char * line) +{ + static int step = 0; + static size_t commlen = 0; + + if (step == 0) { + if (S_TRUE == sh_signify_comp_comm(line, &commlen)) + ++step; + } + else if (step == 1) { + if (S_TRUE == sh_signify_comp_sig(line, commlen)) { + ++step; + } + else { + step = 0; commlen = 0; + } + } + else if (step == 2) { + step = 0; commlen = 0; + return S_TRUE; + } + return S_FALSE; +} + +static +int sh_signify_msg_startdata(const char * line) +{ + (void) line; + return S_TRUE; +} + +static +int sh_signify_msg_end(const char * line) +{ + if (line[0] != '\0') + return S_FALSE; + return S_TRUE; +} + +static +int sh_signify_data_end(const char * line) +{ + if (line[0] == '[' && line[1] == 'E' && line[2] == 'O' && + line[3] == 'F' && line[4] == ']') + return S_TRUE; + else if (line[0] != '\0') + return S_FALSE; + return S_TRUE; +} + +static +SL_TICKET sh_signify_extract_signed(SL_TICKET fd, extractlevel extract_level) +{ + const int fgets_buf_size = 16384; + FILE * fin_cp = NULL; + char * buf = NULL; + int bufc; + char * comment = NULL; + size_t commlen = 0; + + int flag_comm = S_FALSE; + int flag_sig = S_FALSE; + SL_TICKET fdTmp = (-1); + SL_TICKET open_tmp (void); + + /* extract the data and copy to temporary file + */ + fdTmp = open_tmp(); + if (SL_ISERROR(fdTmp)) + { + dlog(1, FIL__, __LINE__, _("Error opening temporary file.\n")); + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, + _("Error opening temporary file."), + _("sh_signify_extract_signed")); + return -1; + } + + fin_cp = fdopen(dup(get_the_fd(fd)), "rb"); + buf = SH_ALLOC(fgets_buf_size); + + while (NULL != fgets(buf, fgets_buf_size, fin_cp)) + { + + bufc = 0; + while (bufc < fgets_buf_size) { + if (buf[bufc] == '\n') { ++bufc; break; } + ++bufc; + } + + if (flag_comm == S_FALSE) + { + if (sh_signify_comp_comm(buf, &commlen) == S_TRUE) + { + flag_comm = S_TRUE; + if (extract_level == SIG_DATASIG) + { + comment = sh_util_strdup(buf); + commlen = bufc; + } + } + continue; + } + else if (flag_comm == S_TRUE && flag_sig == S_FALSE) + { + if (sh_signify_comp_sig(buf, commlen) == S_TRUE) + { + flag_sig = S_TRUE; + if (extract_level == SIG_DATASIG) + { + sl_write(fdTmp, comment, commlen); + sl_write(fdTmp, buf, bufc); + } + if (comment != NULL) + SH_FREE(comment); + comment = NULL; + } + else + { + if (comment != NULL) + SH_FREE(comment); + comment = NULL; commlen = 0; flag_comm = 0; + } + continue; + } + + if (flag_sig == S_TRUE) + { + sl_write(fdTmp, buf, bufc); + } + } + if (comment != NULL) + SH_FREE(comment); + sl_fclose(FIL__, __LINE__, fin_cp); + sl_rewind (fdTmp); + +#if defined(SH_DEBUG_SIGNIFY) + fin_cp = fdopen(dup(get_the_fd(fdTmp)), "rb"); + FILE * fout = fopen("xxx.out", "w+"); + while (NULL != fgets(buf, fgets_buf_size, fin_cp)) + { + fputs(buf, fout); + } + fclose(fout); + sl_rewind(fdTmp); +#endif + + SH_FREE(buf); + return fdTmp; +} + + +static FILE * sh_signify_popen (sh_gpg_popen_t *source, int fd, char * homedir) +{ + char path[256]; + char cc1[32]; + char cc2[32]; + char cc3[32]; + char cc4[SH_PATHBUF+32]; + char cc5[32]; + char cc6[32]; + char * argv[9]; + FILE * retval = NULL; + + struct stat lbuf; + int status_stat = 0; + +#ifdef HAVE_SIG_KEY_HASH + SL_TICKET checkfd; +#endif + + + SL_ENTER(_("sh_signify_popen")); + + sl_strlcpy (path, DEFAULT_SIG_PATH, 256); + + sl_strlcpy (cc1, _("-Vem"), 32); + sl_strlcpy (cc2, _("/dev/null"), 32); + + sl_strlcpy (cc3, _("-p"), 32); + sl_strlcpy (cc4, homedir, SH_PATHBUF+32); + sl_strlcat (cc4, _("/.signify/"), SH_PATHBUF+32); + sl_strlcat (cc4, SH_INSTALL_NAME, SH_PATHBUF+32); + sl_strlcat (cc4, _(".pub"), SH_PATHBUF+32); + + /* read signed message from stdin */ + sl_strlcpy (cc5, _("-x"), 32); + sl_strlcpy (cc6, _("-"), 32); + + status_stat = retry_lstat(FIL__, __LINE__, cc4, &lbuf); + if (status_stat == -1) + { + dlog(1, FIL__, __LINE__, + _("Signify public key %s\ndoes not exist or is not accessible.\nPlease add the directory and put the key there\nto allow signature verification.\n"), + cc4); + sh_error_handle((-1), FIL__, __LINE__, status_stat, MSG_EXIT_ABORT1, + sh.prg_name); + aud_exit (FIL__, __LINE__, EXIT_FAILURE); + } +#ifdef HAVE_SIG_KEY_HASH + checkfd = sl_open_read(FIL__, __LINE__, cc4, SL_YESPRIV); + + if (0 != sh_sig_checksum(checkfd, SIG_HASH_OTHER, SIG_KEY_HASH, cc4)) + { + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, + _("Checksum mismatch for signify public key"), + _("signify_popen")); + sl_close(checkfd); + sh_error_handle((-1), FIL__, __LINE__, status_stat, MSG_EXIT_ABORT1, + sh.prg_name); + aud_exit (FIL__, __LINE__, EXIT_FAILURE); + } + sl_close(checkfd); +#endif + + argv[0] = path; + argv[1] = cc1; + argv[2] = cc2; + argv[3] = cc3; + argv[4] = cc4; + argv[5] = cc5; + argv[6] = cc6; + argv[7] = NULL; + + retval = sh_sig_popen(argv, source, fd); + SL_RETURN((retval), _("sh_signify_popen")); +} + +static +int sh_signify_check_file_sign(int fd, char * homedir) +{ + struct stat buf; + char line[256]; + sh_gpg_popen_t source; + int status = 0; + unsigned int n_goodsig = 0; + unsigned int n_lines = 0; + +#ifdef HAVE_SIG_CHECKSUM + SL_TICKET checkfd; +#endif + + SL_ENTER(_("sh_signify_check_file_sign")); + + /* check whether signify exists and has the correct checksum + */ + TPT(((0), FIL__, __LINE__, _("msg=<Check signature>\n"))); + TPT(((0), FIL__, __LINE__, _("msg=<signify is %s>\n"), DEFAULT_SIG_PATH)); + + if (0 != retry_lstat(FIL__, __LINE__, DEFAULT_SIG_PATH, &buf)) + { + char errbuf[SH_ERRBUF_SIZE]; + + status = errno; + sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT, + sh_error_message(status, errbuf, sizeof(errbuf)), DEFAULT_SIG_PATH); + SL_RETURN( SH_SIG_BAD, _("sh_signify_check_file_sign")); + } + + if (0 != tf_trust_check (DEFAULT_SIG_PATH, SL_YESPRIV)) + SL_RETURN( SH_SIG_BAD, _("sh_signify_check_file_sign")); + +#ifdef HAVE_SIG_CHECKSUM + checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_SIG_PATH, SL_YESPRIV); + + if (0 != sh_sig_checksum(checkfd, SIG_HASH_REPORTFULL, NULL, NULL)) + { + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, + _("Checksum mismatch"), + _("signify_check_file_sign")); + sl_close(checkfd); + SL_RETURN( SH_SIG_BAD, _("sh_signify_check_file_sign")); + } + sl_close(checkfd); +#endif + + TPT(((0), FIL__, __LINE__, _("msg=<Open pipe to check signature>\n"))); + + fflush(NULL); + + source.pipe = sh_signify_popen ( &source, fd, homedir ); + + if (NULL == source.pipe) + { + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, + _("Could not open pipe"), + _("signify_check_file_sign")); + SL_RETURN( SH_SIG_BAD, _("sh_signify_check_file_sign")); + } + + TPT(((0), FIL__, __LINE__, _("msg=<Open pipe success>\n"))); + + xagain: + + errno = 0; + + while (NULL != fgets(line, sizeof(line), source.pipe)) + { + TPT(((0), FIL__, __LINE__, _("msg=<signify out: %s>\n"), line)); + if (line[strlen(line)-1] == '\n') + line[strlen(line)-1] = ' '; + sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN, + line, + _("signify_check_file_sign")); + + ++n_lines; + + /* the '\n' has been replaced with ' ' for logging */ + if (0 == sl_strcmp(_("Signature Verified "), line)) + { + ++n_goodsig; + } + } + + if (ferror(source.pipe) && errno == EAGAIN) + { + /* sleep 10 ms to avoid starving the gpg child writing to the pipe */ + retry_msleep(0,10); + clearerr(source.pipe); + goto xagain; + } + + if (0 != sh_sig_pclose (&source)) + { + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, + _("Error on closing process pipe"), + _("signify_check_file_sign")); + n_goodsig = 0; + } + + TPT(((0), FIL__, __LINE__, _("msg=<Close pipe>\n"))); + + if (n_goodsig == 1 && n_lines == 1) + { + TPT(((0), FIL__, __LINE__, _("msg=<Signature Verified>\n"))); + SL_RETURN( SH_SIG_OK, _("sh_signature_check_file_sign")); + } + else + { + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, + _("Error verifying file signature"), + _("signify_check_file_sign")); + } + SL_RETURN( SH_SIG_BADSIGN, _("sh_signature_check_file_sign")); +} + + +int sh_signify_check_signature (SL_TICKET file, ShSigFile what) +{ + int status = SH_SIG_BAD; + int fd = 0; + + static int smsg = S_FALSE; + + char * homedir = sh.effective.home; + char * home_alloc = NULL; +#if defined(SH_WITH_SERVER) + struct passwd * tempres; +#if defined(USE_GETPWNAM_R) + struct passwd pwd; + char * buffer = SH_ALLOC(SH_PWBUF_SIZE); +#endif +#endif + + SL_ENTER(_("sh_signify_check_sign")); + + (void) what; + + fd = get_the_fd(file); + + if (fd < 0) + { + TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd)); + dlog(1, FIL__, __LINE__, + _("This looks like an unexpected internal error.\n")); +#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R) + SH_FREE(buffer); +#endif + SL_RETURN( (-1), _("sh_signify_check_sign")); + } + +#if defined(SH_WITH_SERVER) +#if defined(USE_GETPWNAM_R) + sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres); +#else + tempres = sh_getpwnam(DEFAULT_IDENT); +#endif + if ((tempres != NULL) && (0 == sl_ret_euid())) + { + /* privileges not dropped yet*/ + homedir = tempres->pw_dir; + } +#endif + + home_alloc = sh_util_strdup(homedir); + + TPT(((0), FIL__, __LINE__, _("msg=<SIGNIFY_CHECK: FD = %d>\n"), fd)); + status = sh_signify_check_file_sign(fd, homedir); + + if (status != SH_SIG_OK) + { + TPT(((0), FIL__, __LINE__, _("msg=<Status = %d>\n"), status)); + dlog(1, FIL__, __LINE__, + _("The signature of the configuration file or the file signature database\ncould not be verified. Possible reasons are:\n - signify binary (%s) not found\n - invalid signature\n - there is no keyfile in %s/.signify/%s.pub, or\n - the file is not signed - did you move /filename.sig to /filename ?\nTo create a signed file, use (remove old signatures before):\n signify|signify-openbsd -Se -s KEYNAME.sec -m FILE\n mv FILE.sig FILE\n"), + DEFAULT_SIG_PATH, home_alloc, SH_INSTALL_NAME); + SH_FREE(home_alloc); + SL_RETURN( (-1), _("sh_signify_check_sign")); + } + + if (smsg == S_FALSE) + { + sh_sig_fill_startup (__LINE__, + sh.prg_name, sh.real.uid, + (sh.flag.hidefile == S_TRUE) ? + _("(hidden)") : file_path('C', 'R'), + NULL, NULL); + } + smsg = S_TRUE; + + SH_FREE(home_alloc); + SL_RETURN(0, _("sh_signify_check_sign")); +} + +/* This is GPG specific stuff + */ +#elif defined(WITH_GPG) +static FILE * sh_gpg_popen (sh_gpg_popen_t *source, int fd, char * homedir) +{ + char path[256]; + char cc1[32]; + char cc2[32]; + + char cc0[2] = "-"; + char cc3[32]; + char cc4[SH_PATHBUF+32]; + char cc5[32]; + char * argv[9]; + FILE * retval = NULL; + + + SL_ENTER(_("sh_gpg_popen")); + + /* -- GnuPG -- */ + sl_strlcpy (path, DEFAULT_SIG_PATH, 256); + sl_strlcpy (cc1, _("--status-fd"), 32); + sl_strlcpy (cc2, _("--verify"), 32); + sl_strlcpy (cc3, _("--homedir"), 32); + /* sl_strlcpy (cc4, sh.effective.home, SH_PATHBUF+32); */ + sl_strlcpy (cc4, homedir, SH_PATHBUF+32); + sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32); + sl_strlcpy (cc5, _("--no-tty"), 32); + +#if defined(SH_WITH_SERVER) + if (0 == sl_ret_euid()) /* privileges not dropped yet */ + { + struct stat lbuf; + int status_stat = 0; +#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R) + struct passwd pwd; + char * buffer = SH_ALLOC(SH_PWBUF_SIZE); + struct passwd * tempres; + sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres); +#else + struct passwd * tempres = sh_getpwnam(DEFAULT_IDENT); +#endif + + if (!tempres) + { + dlog(1, FIL__, __LINE__, + _("User %s does not exist. Please add the user to your system.\n"), + DEFAULT_IDENT); + status_stat = -1; + } + if (!tempres->pw_dir || tempres->pw_dir[0] == '\0') + { + dlog(1, FIL__, __LINE__, + _("User %s does not have a home directory.\nPlease add the home directory for this user to your system.\n"), + DEFAULT_IDENT); + status_stat = -2; + } + if (status_stat == 0) + { + sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32); + sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32); + status_stat = retry_lstat(FIL__, __LINE__, cc4, &lbuf); + if (status_stat == -1) + { + dlog(1, FIL__, __LINE__, + _("Gnupg directory %s for user %s\ndoes not exist or is not accessible.\nPlease add the directory and put the keyring (pubring.gpg or pubring.kbx) there\nto verify the configuration file.\n"), + cc4, DEFAULT_IDENT); + status_stat = -3; + } + } + if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid) + { + dlog(1, FIL__, __LINE__, + _("Gnupg directory %s\nis not owned by user %s.\n"), + cc4, DEFAULT_IDENT); + status_stat = -4; + } + if (status_stat == 0) + { + char cc4_test[SH_PATHBUF+32]; + + sl_strlcpy(cc4_test, cc4, SH_PATHBUF+32); + sl_strlcat (cc4_test, _("/pubring.gpg"), SH_PATHBUF+32); + + status_stat = retry_lstat(FIL__, __LINE__, cc4_test, &lbuf); + if (status_stat == -1) + { + sl_strlcpy(cc4_test, cc4, SH_PATHBUF+32); + sl_strlcat (cc4_test, _("/pubring.kbx"), SH_PATHBUF+32); + + status_stat = retry_lstat(FIL__, __LINE__, cc4_test, &lbuf); + if (status_stat == -1) + { + sl_strlcpy(cc4_test, cc4, SH_PATHBUF+32); + sl_strlcat (cc4_test, _("/pubring.(gpg|kbx)"), SH_PATHBUF+32); + + dlog(1, FIL__, __LINE__, + _("Gnupg public keyring %s for user %s\ndoes not exist or is not accessible.\nPlease add the directory and put the keyring (pubring.gpg or pubring.kbx) there\nto verify the configuration file.\n"), + cc4_test, DEFAULT_IDENT); + status_stat = -5; + } + } + } + if (status_stat == 0 && lbuf.st_uid != tempres->pw_uid) + { + dlog(1, FIL__, __LINE__, + _("Gnupg public keyring %s\nis not owned by user %s.\n"), + cc4, DEFAULT_IDENT); + status_stat = -6; + } + if (status_stat != 0) + { + sh_error_handle((-1), FIL__, __LINE__, status_stat, MSG_EXIT_ABORT1, + sh.prg_name); + aud_exit (FIL__, __LINE__, EXIT_FAILURE); + } + sl_strlcpy (cc4, tempres->pw_dir, SH_PATHBUF+32); + sl_strlcat (cc4, _("/.gnupg"), SH_PATHBUF+32); +#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETPWNAM_R) + SH_FREE(buffer); +#endif + } +#endif + + argv[0] = path; + argv[1] = cc1; + argv[2] = "1"; + argv[3] = cc2; + argv[4] = cc3; + argv[5] = cc4; + argv[6] = cc5; + argv[7] = cc0; + argv[8] = NULL; + + retval = sh_sig_popen(argv, source, fd); + SL_RETURN((retval), _("sh_gpg_popen")); +} + +static +int sh_gpg_check_file_sign(int fd, char * sign_id, char * sign_fp, + char * homedir, ShSigFile whichfile) +{ + struct stat buf; + char line[256]; + sh_gpg_popen_t source; + int have_id = BAD, have_fp = BAD, status = 0; + unsigned int n_newsig = 0; + unsigned int n_goodsig = 0; + unsigned int n_validsig = 0; + +#ifdef HAVE_SIG_CHECKSUM + SL_TICKET checkfd; +#endif + + SL_ENTER(_("sh_gpg_check_file_sign")); + + /* check whether GnuPG exists and has the correct checksum + */ + TPT(((0), FIL__, __LINE__, _("msg=<Check signature>\n"))); + TPT(((0), FIL__, __LINE__, _("msg=<gpg is %s>\n"), DEFAULT_SIG_PATH)); + + if (0 != retry_lstat(FIL__, __LINE__, DEFAULT_SIG_PATH, &buf)) + { + char errbuf[SH_ERRBUF_SIZE]; + + status = errno; + sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, status, MSG_ERR_LSTAT, + sh_error_message(status, errbuf, sizeof(errbuf)), DEFAULT_SIG_PATH); + SL_RETURN( SH_SIG_BAD, _("sh_gpg_check_file_sign")); + } + + if (0 != tf_trust_check (DEFAULT_SIG_PATH, SL_YESPRIV)) + SL_RETURN( SH_SIG_BAD, _("sh_gpg_check_file_sign")); + +#ifdef HAVE_SIG_CHECKSUM + checkfd = sl_open_read(FIL__, __LINE__, DEFAULT_SIG_PATH, SL_YESPRIV); + + if (0 != sh_sig_checksum(checkfd, SIG_HASH_REPORTFULL, NULL, NULL)) + { + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, + _("Checksum mismatch"), + _("gpg_check_file_sign")); + sl_close(checkfd); + SL_RETURN( SH_SIG_BAD, _("sh_gpg_check_file_sign")); + } + sl_close(checkfd); +#endif + + TPT(((0), FIL__, __LINE__, _("msg=<Open pipe to check signature>\n"))); + + fflush(NULL); + + source.pipe = sh_gpg_popen ( &source, fd, homedir ); + + if (NULL == source.pipe) + { + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, + _("Could not open pipe"), + _("gpg_check_file_sign")); + SL_RETURN( SH_SIG_BAD, _("sh_gpg_check_file_sign")); + } + + TPT(((0), FIL__, __LINE__, _("msg=<Open pipe success>\n"))); + + xagain: + + errno = 0; + + while (NULL != fgets(line, sizeof(line), source.pipe)) + { + + TPT(((0), FIL__, __LINE__, _("msg=<gpg out: %s>\n"), line)); + if (line[strlen(line)-1] == '\n') + line[strlen(line)-1] = ' '; + sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN, + line, + _("gpg_check_file_sign")); + + if (sl_strlen(line) < 12) + continue; + + /* Sun May 27 18:40:05 CEST 2001 + */ + if (0 == sl_strncmp(_("BADSIG"), &line[9], 6) || + 0 == sl_strncmp(_("ERRSIG"), &line[9], 6) || + 0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6) || + 0 == sl_strncmp(_("NODATA"), &line[9], 6) || + 0 == sl_strncmp(_("ERROR"), &line[9], 5) || + 0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6)) + { + if (0 == sl_strncmp(_("BADSIG"), &line[9], 6)) { + dlog(1, FIL__, __LINE__, + _("%s file is signed, but the signature is invalid."), + ((whichfile == SIG_CONF) ? _("Configuration") : _("Database"))); + } + else if (0 == sl_strncmp(_("NO_PUBKEY"), &line[9], 6)) { + dlog(1, FIL__, __LINE__, + _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."), + ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")), + homedir); + } + else if (0 == sl_strncmp(_("ERRSIG"), &line[9], 6)) { + dlog(1, FIL__, __LINE__, + _("%s file is signed, but the public key to verify the signature is not in my keyring %s/.gnupg/pubring.asc."), + ((whichfile == SIG_CONF) ? _("Configuration") : _("Database")), + homedir); + } + else if (0 == sl_strncmp(_("SIGEXPIRED"), &line[9], 6)) { + dlog(1, FIL__, __LINE__, + _("%s file is signed, but the public key to verify the signature has expired."), + ((whichfile == SIG_CONF) ? _("Configuration") : _("Database"))); + } + else if (0 == sl_strncmp(_("NODATA"), &line[9], 6)) { + dlog(1, FIL__, __LINE__, + _("%s file is not signed."), + ((whichfile == SIG_CONF) ? _("Configuration") : _("Database"))); + } + else if (0 == sl_strncmp(_("ERROR"), &line[9], 5)) { + dlog(1, FIL__, __LINE__, + _("%s file is not correctly signed. An error occured while verifying the signature."), + ((whichfile == SIG_CONF) ? _("Configuration") : _("Database"))); + } + + have_fp = BAD; have_id = BAD; + break; + } + if (0 == sl_strncmp(_("GOODSIG"), &line[9], 7)) + { + ++n_goodsig; + sl_strlcpy (sign_id, &line[25], SH_MINIBUF+1); + if (sign_id) + sign_id[sl_strlen(sign_id)-1] = '\0'; /* remove trailing '"' */ + have_id = GOOD; + } + else if (0 == sl_strncmp(_("VALIDSIG"), &line[9], 8)) + { + ++n_validsig; + strncpy (sign_fp, &line[18], 40); + sign_fp[40] = '\0'; + have_fp = GOOD; + } + else if (0 == sl_strncmp(_("NEWSIG"), &line[9], 6)) + { + ++n_newsig; + } + + } + + if (ferror(source.pipe) && errno == EAGAIN) + { + /* sleep 10 ms to avoid starving the gpg child writing to the pipe */ + retry_msleep(0,10); + clearerr(source.pipe); + goto xagain; + } + + if (0 != sh_sig_pclose (&source)) + { + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, + _("Error on closing process pipe"), + _("gpg_check_file_sign")); + have_id = BAD; + } + + TPT(((0), FIL__, __LINE__, _("msg=<Close pipe>\n"))); + + if (n_goodsig != n_validsig || n_newsig > 1 || n_goodsig > 1) + { + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, + _("Too many or invalid signatures"), + _("gpg_check_file_sign")); + have_id = BAD; + } + + if (have_id == GOOD) + { + TPT(((0), FIL__, __LINE__, _("msg=<Got signator ID>\n"))); + } + if (have_fp == GOOD) + { + TPT(((0), FIL__, __LINE__, _("msg=<Got fingerprint>\n"))); + } + + if (have_id == GOOD && have_fp == GOOD) + SL_RETURN( SH_SIG_OK, _("sh_gpg_check_file_sign")); + else + { + if (have_id == BAD) + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, + _("No good signature"), + _("gpg_check_file_sign")); + else + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, + _("No fingerprint for key"), + _("gpg_check_file_sign")); + SL_RETURN( SH_SIG_BADSIGN, _("sh_gpg_check_file_sign")); + } +} + +#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && \ + defined(HAVE_GETPWNAM_R) +#define USE_GETPWNAM_R 1 +#endif + +static +int sh_gpg_check_signature (SL_TICKET file, ShSigFile what) +{ + int status = SH_SIG_BAD; + int fd = 0; + + static int smsg = S_FALSE; + char * tmp; + + char * sig_id; + char * sig_fp; + + char * homedir = sh.effective.home; +#if defined(SH_WITH_SERVER) + struct passwd * tempres; +#if defined(USE_GETPWNAM_R) + struct passwd pwd; + char * buffer = SH_ALLOC(SH_PWBUF_SIZE); +#endif +#endif + +#ifdef USE_FINGERPRINT +#include "sh_gpg_fp.h" +#endif + + SL_ENTER(_("sh_gpg_check_sign")); + + + if (what == SIG_CONF) + fd = get_the_fd(file); + if (what == SIG_DATA) + fd = get_the_fd(file); + + + if (fd < 0) + { + TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd)); + dlog(1, FIL__, __LINE__, + _("This looks like an unexpected internal error.\n")); +#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R) + SH_FREE(buffer); +#endif + SL_RETURN( (-1), _("sh_gpg_check_sign")); + } + +#if defined(SH_WITH_SERVER) +#if defined(USE_GETPWNAM_R) + sh_getpwnam_r(DEFAULT_IDENT, &pwd, buffer, SH_PWBUF_SIZE, &tempres); +#else + tempres = sh_getpwnam(DEFAULT_IDENT); +#endif + if ((tempres != NULL) && (0 == sl_ret_euid())) + { + /* privileges not dropped yet*/ + homedir = tempres->pw_dir; + } +#endif + + if (what == SIG_CONF) + { + TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd)); + status = sh_gpg_check_file_sign(fd, gp.conf_id, gp.conf_fp, homedir, SIG_CONF); + TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGUSR: |%s|>\n"), gp.conf_id)); + TPT(((0), FIL__, __LINE__, _("msg=<CONF SIGFP: |%s|>\n"), gp.conf_fp)); + sig_id = gp.conf_id; sig_fp = gp.conf_fp; + } + + if (what == SIG_DATA) + { + TPT(((0), FIL__, __LINE__, _("msg=<GPG_CHECK: FD = %d>\n"), fd)); + status = sh_gpg_check_file_sign(fd, gp.data_id, gp.data_fp, homedir, SIG_DATA); + TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGUSR: |%s|>\n"), gp.data_id)); + TPT(((0), FIL__, __LINE__, _("msg=<DATA SIGFP: |%s|>\n"), gp.data_fp)); + sig_id = gp.data_id; sig_fp = gp.data_fp; + } + + if (SH_SIG_OK == status) + { +#ifdef USE_FINGERPRINT + if ((sl_strcmp(SH_GPG_FP, sig_fp) == 0)) + { + int i; + + for(i = 0; i < (int) sl_strlen(sig_fp); ++i) { + if (gpgfp[i] != sig_fp[i]) { + sh_error_handle(SH_ERR_SEVERE, FIL__, __LINE__, 0, + MSG_E_GPG_FP, gpgfp, sig_fp); + break; } + } + + if (smsg == S_FALSE) { + tmp = sh_util_safe_name(sig_id); + sh_sig_fill_startup (__LINE__, sh.prg_name, sh.real.uid, + (sh.flag.hidefile == S_TRUE) ? + _("(hidden)") : file_path('C', 'R'), + tmp, + sig_fp); + SH_FREE(tmp); } + smsg = S_TRUE; + +#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R) + SH_FREE(buffer); +#endif + SL_RETURN(0, _("sh_gpg_check_sign")); + } + else + { + /* fp mismatch */ + dlog(1, FIL__, __LINE__, + _("The fingerprint of the signing key: %s\ndoes not match the compiled-in fingerprint: %s.\nTherefore the signature could not be verified.\n"), + sig_fp, SH_GPG_FP); + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, + _("Fingerprint mismatch"), _("gpg_check_sign")); + status = SH_SIG_BADSIGN; + } +#else /* ifdef USE_FINGERPRINT */ + if (smsg == S_FALSE) + { + tmp = sh_util_safe_name(sig_id); + sh_sig_fill_startup (__LINE__, + sh.prg_name, sh.real.uid, + (sh.flag.hidefile == S_TRUE) ? + _("(hidden)") : file_path('C', 'R'), + tmp, sig_fp); + SH_FREE(tmp); + } + smsg = S_TRUE; + +#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R) + SH_FREE(buffer); +#endif + + /* status == OK and no fp checking */ + SL_RETURN(0, _("sh_gpg_check_sign")); +#endif /* !ifdef USE_FINGERPRINT */ + } + + if (status != SH_SIG_OK) + { + uid_t e_uid = sl_ret_euid(); + char * e_home = sh.effective.home; + +#if defined(SH_WITH_SERVER) +#if defined(USE_GETPWNAM_R) + struct passwd e_pwd; + char * e_buffer = SH_ALLOC(SH_PWBUF_SIZE); + struct passwd * e_tempres; + sh_getpwnam_r(DEFAULT_IDENT, &e_pwd, e_buffer, SH_PWBUF_SIZE, &e_tempres); +#else + struct passwd * e_tempres = sh_getpwnam(DEFAULT_IDENT); +#endif + + if ((e_tempres != NULL) && (0 == sl_ret_euid())) + { + /* privileges not dropped yet */ + e_uid = e_tempres->pw_uid; + e_home = e_tempres->pw_dir; + } +#endif + dlog(1, FIL__, __LINE__, + _("The signature of the configuration file or the file signature database\ncould not be verified. Possible reasons are:\n - gpg binary (%s) not found\n - invalid signature\n - the signature key is not in the private keyring of UID %d,\n - there is no keyring in %s/.gnupg, or\n - the file is not signed - did you move /filename.asc to /filename ?\nTo create a signed file, use (remove old signatures before):\n gpg -a --clearsign --not-dash-escaped FILE\n mv FILE.asc FILE\n"), + DEFAULT_SIG_PATH, + (int) e_uid, e_home); + +#if defined(SH_WITH_SERVER) && defined(USE_GETPWNAM_R) + SH_FREE(e_buffer); +#endif + } + + TPT(((0), FIL__, __LINE__, _("msg=<Status = %d>\n"), status)); + + SL_RETURN(-1, _("sh_gpg_check_sign")); /* make compiler happy */ +} + +static int sh_gpg_comp(const char * line, const char * cmp) +{ + int retval = S_FALSE; + + if (line && line[0] == '-' && line[1] == '-') + { + char * dup = sh_util_strdup(line); + char * tmp = dup + sl_strlen( dup ); + --tmp; + if (*tmp == '\n') { *tmp = '\0'; --tmp; } + while( (*tmp == '\t' || *tmp == ' ' || *tmp == '\r' ) && tmp >= dup ) *tmp-- = '\0'; + + if (0 == sl_strcmp(dup, cmp)) + retval = S_TRUE; + SH_FREE(dup); + } + return retval; +} + +static +int sh_gpg_msg_start(const char * line) +{ + static char cmp[SH_MINIBUF]; + static int initialized = 0; + + if (initialized == 0) { + sl_strlcpy(cmp, _("-----BEGIN PGP SIGNED MESSAGE-----"), sizeof(cmp)); + initialized = 1; + } + return sh_gpg_comp(line, cmp); +} + +static +int sh_gpg_msg_startdata(const char * line) +{ + if (line[0] == '\n') + return S_TRUE; + return S_FALSE; +} + +static +int sh_gpg_msg_end(const char * line) +{ + static char cmp[SH_MINIBUF]; + static int initialized = 0; + + if (initialized == 0) { + sl_strlcpy(cmp, _("-----BEGIN PGP SIGNATURE-----"), sizeof(cmp)); + initialized = 1; + } + return sh_gpg_comp(line, cmp); +} + +static +int sh_gpg_sig_end(const char * line) +{ + static char cmp[SH_MINIBUF]; + static int initialized = 0; + + if (initialized == 0) { + sl_strlcpy(cmp, _("-----END PGP SIGNATURE-----"), sizeof(cmp)); + initialized = 1; + } + return sh_gpg_comp(line, cmp); +} + +static +SL_TICKET sh_gpg_extract_signed(SL_TICKET fd, extractlevel extract_level) +{ + const int fgets_buf_size = 16384; + FILE * fin_cp = NULL; + char * buf = NULL; + int bufc; + int flag_pgp = S_FALSE; + int flag_nohead = S_FALSE; + SL_TICKET fdTmp = (-1); + SL_TICKET open_tmp (void); + + /* extract the data and copy to temporary file + */ + fdTmp = open_tmp(); + if (SL_ISERROR(fdTmp)) + { + dlog(1, FIL__, __LINE__, _("Error opening temporary file.\n")); + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN, + _("Error opening temporary file."), + _("sh_gpg_extract_signed")); + return -1; + } + + fin_cp = fdopen(dup(get_the_fd(fd)), "rb"); + buf = SH_ALLOC(fgets_buf_size); + + while (NULL != fgets(buf, fgets_buf_size, fin_cp)) + { + bufc = 0; + while (bufc < fgets_buf_size) { + if (buf[bufc] == '\n') { ++bufc; break; } + ++bufc; + } + + if (flag_pgp == S_FALSE && sh_gpg_msg_start(buf) == S_TRUE) + { + flag_pgp = S_TRUE; + if (extract_level == SIG_DATASIG) + sl_write(fdTmp, buf, bufc); + continue; + } + + if (flag_pgp == S_TRUE && flag_nohead == S_FALSE) + { + /* Header finished */ + if (buf[0] == '\n') + { + flag_nohead = S_TRUE; + if (extract_level == SIG_DATASIG) + sl_write(fdTmp, buf, 1); + continue; + } + /* copy these headers */ + else if (0 == sl_strncmp(buf, _("Hash:"), 5) || + 0 == sl_strncmp(buf, _("NotDashEscaped:"), 15)) + { + if (extract_level == SIG_DATASIG) + sl_write(fdTmp, buf, bufc); + continue; + } + /* ignore other headers */ + else + continue; + } + + if (flag_pgp == S_TRUE && buf[0] == '\n') + { + sl_write(fdTmp, buf, 1); + } + else if (flag_pgp == S_TRUE) + { + if (extract_level == SIG_DATASIG) { + sl_write(fdTmp, buf, bufc); + } + else { + if (sh_gpg_msg_end(buf) == S_TRUE) + break; + else + sl_write(fdTmp, buf, bufc); + } + } + + /* This is after the copy has been done. */ + if (flag_pgp == S_TRUE && sh_gpg_sig_end(buf) == S_TRUE) + break; + } + SH_FREE(buf); + sl_fclose(FIL__, __LINE__, fin_cp); + sl_rewind (fdTmp); + + return fdTmp; +} +#endif + +/********************************************************************* + * + * Exported functions + * + *********************************************************************/ + +int sh_sig_check_signature (SL_TICKET file, ShSigFile what) +{ +#if defined(WITH_GPG) + return sh_gpg_check_signature (file, what); +#elif defined(WITH_SIGNIFY) + return sh_signify_check_signature (file, what); +#else + return -1; +#endif +} + +SL_TICKET sh_sig_extract_signed(SL_TICKET fd) +{ +#if defined(WITH_GPG) + return sh_gpg_extract_signed(fd, SIG_DATASIG); +#elif defined(WITH_SIGNIFY) + return sh_signify_extract_signed(fd, SIG_DATASIG); +#else + return -1; +#endif +} + +SL_TICKET sh_sig_extract_signed_data(SL_TICKET fd) +{ +#if defined(WITH_GPG) + return sh_gpg_extract_signed(fd, SIG_DATAONLY); +#elif defined(WITH_SIGNIFY) + return sh_signify_extract_signed(fd, SIG_DATAONLY); +#else + return -1; +#endif +} + +int sh_sig_msg_start(const char * line) +{ +#if defined(WITH_GPG) + return sh_gpg_msg_start(line); +#elif defined(WITH_SIGNIFY) + return sh_signify_msg_start(line); +#else + return -1; +#endif +} + +int sh_sig_msg_startdata(const char * line) +{ +#if defined(WITH_GPG) + return sh_gpg_msg_startdata(line); +#elif defined(WITH_SIGNIFY) + return sh_signify_msg_startdata(line); +#else + return -1; +#endif +} + +int sh_sig_msg_end(const char * line) +{ +#if defined(WITH_GPG) + return sh_gpg_msg_end(line); +#elif defined(WITH_SIGNIFY) + return sh_signify_msg_end(line); +#else + return -1; +#endif +} + +int sh_sig_data_end(const char * line) +{ +#if defined(WITH_GPG) + return sh_gpg_sig_end(line); +#elif defined(WITH_SIGNIFY) + return sh_signify_data_end(line); +#else + return -1; +#endif +} + +void sh_sig_log_startup (void) +{ + if (startInfo.program != NULL) + { + sh_error_handle ((-1), FIL__, startInfo.line, 0, MSG_START_GH, + startInfo.program, startInfo.uid, + startInfo.path, + startInfo.key_uid, startInfo.key_id); + } + return; +} + +/* #ifdef WITH_SIG */ +#endif + + + + + + + + diff --git a/src/sh_socket.c b/src/sh_socket.c index f4e9f56..e75433b 100644 --- a/src/sh_socket.c +++ b/src/sh_socket.c @@ -808,7 +808,7 @@ static int get_peer_uid(int talkfd) #endif #if defined(NEED_PASSWORD_AUTH) -char * check_password(char * message, int * client_uid, int talkfd) +char * check_password(char * message, size_t msglen, int * client_uid, int talkfd) { char * cmd = NULL; char * eopw = NULL; @@ -822,7 +822,7 @@ char * check_password(char * message, int * client_uid, int talkfd) * message is null-terminated and >> goodpassword */ if (0 == strcmp(goodpassword, message) && - strlen(goodpassword) < (sizeof(message)/2)) + strlen(goodpassword) < (msglen/2)) { *client_uid = sh_socket_flaguid; cmd = &message[strlen(goodpassword)+1]; @@ -901,7 +901,7 @@ int sh_socket_read (struct socket_cmd * srvcmd) cmd = message; #elif defined(NEED_PASSWORD_AUTH) - cmd = check_password(message, &client_uid, talkfd); + cmd = check_password(message, sizeof(message), &client_uid, talkfd); #else sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN, diff --git a/src/sh_srp.c b/src/sh_srp.c index ecc757c..ab6cbcf 100644 --- a/src/sh_srp.c +++ b/src/sh_srp.c @@ -47,14 +47,14 @@ int big_errno = BIG_OK; #define bignum MP_INT -inline +static int big_create (bignum * a) { mpz_init(a); return 0; } -inline +static int big_zerop (bignum * a) { mpz_t b; @@ -68,14 +68,14 @@ int big_zerop (bignum * a) return 1; } -inline +static int big_trunc (bignum * a, bignum * b, bignum * q, bignum *r) { mpz_tdiv_qr(q, r, a, b); return 0; } -inline +static int big_exptmod (bignum * a, bignum * b, bignum * c, bignum *d) { mpz_powm(d, a, b, c); @@ -118,7 +118,13 @@ char * big_string (bignum * a, int base) if (ptr) get_str_internal = ptr; else - { free(get_str_internal); get_str_internal = NULL; } + { + /* "If realloc() fails, the original block is left untouched; + * it is not freed or moved." */ + /* cppcheck-suppress doubleFree */ + free(get_str_internal); + get_str_internal = NULL; + } } if (get_str_internal == NULL) { @@ -135,34 +141,34 @@ char * big_string (bignum * a, int base) return get_str_internal; } -inline +static int big_add(bignum * a, bignum * b, bignum * c) { mpz_add(c, a, b); return 0; } -inline +static int big_sub(bignum * a, bignum * b, bignum * c) { mpz_sub(c, a, b); return 0; } -inline +static int big_mul(bignum * a, bignum * b, bignum * c) { mpz_mul(c, a, b); return 0; } -inline +static int big_greaterp(bignum * a, bignum * b) { return mpz_cmp(a, b) > 0; } -inline +static int big_set_big(bignum * a, bignum * b) { mpz_set(b, a); @@ -170,7 +176,7 @@ int big_set_big(bignum * a, bignum * b) } -inline +static int big_set_string(const char * str, int base, bignum * a) { mpz_set_str (a, str, base); diff --git a/src/sh_static.c b/src/sh_static.c index 99ce783..f517b93 100644 --- a/src/sh_static.c +++ b/src/sh_static.c @@ -463,8 +463,9 @@ struct group * sh_getgrent(void) int sh_initgroups(const char *user, gid_t gid) { FILE *grf; - gid_t *group_list; - int num_groups, rv; + gid_t *group_list = NULL; + size_t num_groups; + int rv; char **m; struct group group; @@ -473,7 +474,7 @@ int sh_initgroups(const char *user, gid_t gid) rv = -1; /* We alloc space for 8 gids at a time. */ - if (((group_list = calloc(8,sizeof(gid_t *))) != NULL) + if (buff && ((group_list = calloc(8,sizeof(gid_t *))) != NULL) && ((grf = fopen(_PATH_GROUP, "r")) != NULL) ) { @@ -488,14 +489,21 @@ int sh_initgroups(const char *user, gid_t gid) for (m=group.gr_mem ; *m ; m++) { if (!strcmp(*m, user)) { if (!(num_groups & 7)) { - gid_t *tmp = (gid_t *) - realloc(group_list, - (num_groups+8) * sizeof(gid_t *)); - if (!tmp) { - rv = -1; - goto DO_CLOSE; - } - group_list = tmp; + gid_t *tmp = NULL; + if (num_groups > (SIZE_MAX - 8)) { + rv = -1; + goto DO_CLOSE; + } + if ((num_groups+8) <= (SIZE_MAX / sizeof(gid_t *))) { + tmp = (gid_t *) + realloc(group_list, + (num_groups+8) * sizeof(gid_t *)); + } + if (!tmp) { + rv = -1; + goto DO_CLOSE; + } + group_list = tmp; } group_list[num_groups++] = group.gr_gid; break; @@ -511,8 +519,9 @@ int sh_initgroups(const char *user, gid_t gid) /* group_list will be NULL if initial malloc failed, which may trigger * warnings from various malloc debuggers. */ - free(group_list); - free(buff); + if (group_list) free(group_list); + if (buff) free(buff); + /* cppcheck-suppress resourceLeak */ return rv; } @@ -907,7 +916,7 @@ static int __searchdomains; static char * __searchdomain[MAX_SEARCH]; #undef DEBUG -/*#define DEBUG*/ +/* #define DEBUG */ #ifdef DEBUG /* flawfinder: ignore *//* definition of debug macro */ @@ -999,13 +1008,15 @@ static int __length_dotted(const unsigned char *data, int offset) return -1; do { - - if (offset < INT_MAX) + l = data[offset]; + if (offset < INT_MAX) offset++; else return -1; - - l = data[offset]; + if (!l) + break; + + DPRINTF("l[%d] = %d\n", offset, l); if ((l & 0xc0) == (0xc0)) { if (offset < INT_MAX) @@ -1022,6 +1033,7 @@ static int __length_dotted(const unsigned char *data, int offset) } while (l); + DPRINTF("orig: %d now %d\n", orig_offset, offset); return offset - orig_offset; } @@ -1264,7 +1276,7 @@ static int __dns_lookup(const char *name, int type, int nscount, char **nsip, h.qdcount = 1; h.rd = 1; - DPRINTF("encoding header\n", h.rd); + DPRINTF("encoding header %d\n", h.rd); i = __encode_header(&h, packet, PACKETSZ); if (i < 0) @@ -1470,6 +1482,7 @@ static void __open_etc_hosts(FILE **fp) if ((*fp = fopen("/etc/hosts", "r")) == NULL) { *fp = fopen("/etc/config/hosts", "r"); } + /* cppcheck-suppress resourceLeak */ return; } @@ -1545,6 +1558,9 @@ static int __read_etc_hosts_r(FILE * fp, const char * name, int type, } *h_errnop=HOST_NOT_FOUND; + if (fp == NULL) { + return ret; + } while (fgets(buf, buflen, fp)) { if ((cp = strchr(buf, '#'))) *cp = '\0'; @@ -1713,6 +1729,7 @@ static int sh_gethostbyname_r(const char * name, int __nameserversXX; char ** __nameserverXX; + DPRINTF("sh_gethostbyname_r: /%s/\n", name); __open_nameservers(); *result=NULL; @@ -1756,7 +1773,7 @@ static int sh_gethostbyname_r(const char * name, if (buflen<256) return ERANGE; - strncpy(buf, name, buflen); + strncpy(buf, name, buflen-1); /* First check if this is already an address */ if (inet_aton(name, in)) { @@ -1783,7 +1800,7 @@ static int sh_gethostbyname_r(const char * name, return TRY_AGAIN; } - strncpy(buf, a.dotted, buflen); + strncpy(buf, a.dotted, buflen-1); free(a.dotted); if (a.atype == T_CNAME) { /* CNAME */ @@ -1813,6 +1830,7 @@ static int sh_gethostbyname_r(const char * name, } else { free(packet); *h_errnop=HOST_NOT_FOUND; + DPRINTF("host_not_found\n"); return TRY_AGAIN; } } @@ -1829,9 +1847,9 @@ struct hostent * sh_gethostbyname(const char *name) sizeof(struct in_addr *)*2 + sizeof(char *)*(ALIAS_DIM) + 256/*namebuffer*/ + 32/* margin */]; struct hostent *hp; - + + DPRINTF("sh_gethostbyname: /%s/\n", name); sh_gethostbyname_r(name, &h, buf, sizeof(buf), &hp, &h_errno); - return hp; } @@ -1890,6 +1908,7 @@ static int sh_gethostbyaddr_r (const void *addr, socklen_t len, int type, int __nameserversXX; char ** __nameserverXX; + DPRINTF("sh_gethostbyaddr_r called\n"); *result=NULL; if (!addr) return EINVAL; @@ -2002,7 +2021,7 @@ static int sh_gethostbyaddr_r (const void *addr, socklen_t len, int type, return TRY_AGAIN; } - strncpy(buf, a.dotted, buflen); + strncpy(buf, a.dotted, buflen-1); free(a.dotted); if (a.atype == T_CNAME) { /* CNAME */ @@ -2060,6 +2079,7 @@ struct hostent * sh_gethostbyaddr (const void *addr, socklen_t len, int type) sizeof(char *)*(ALIAS_DIM) + 256/*namebuffer*/ + 32/* margin */]; struct hostent *hp; + DPRINTF("sh_gethostbyaddr called\n"); sh_gethostbyaddr_r(addr, len, type, &h, buf, sizeof(buf), &hp, &h_errno); return hp; diff --git a/src/sh_string.c b/src/sh_string.c index a898dd9..58e8c06 100644 --- a/src/sh_string.c +++ b/src/sh_string.c @@ -643,7 +643,8 @@ sh_string * sh_string_replace(const sh_string * s, { len = (size_t) tlen; - if (tlen > 0 && r->siz > (r->len + len)) + if (tlen > 0 && r->siz > (r->len + len) && + &(s->str[ovector[last]]) ) { memcpy(p, &(s->str[ovector[last]]), (size_t)len); p += len; @@ -674,7 +675,8 @@ sh_string * sh_string_replace(const sh_string * s, if (tlen > 0) { len = (size_t)tlen; - if (r->siz >= (r->len + len)) { + if (r->siz >= (r->len + len) && + &(s->str[ovector[2*i -1]]) ) { memcpy(p, &(s->str[ovector[2*i -1]]), (size_t)len); p += (len - 1); r->len += (len - 1); diff --git a/src/sh_subuid.c b/src/sh_subuid.c new file mode 100644 index 0000000..33bf407 --- /dev/null +++ b/src/sh_subuid.c @@ -0,0 +1,245 @@ +/* SAMHAIN file system integrity testing */ +/* Copyright (C) 2018 Rainer Wichmann */ +/* */ +/* This program is free software; you can redistribute it */ +/* and/or modify */ +/* it under the terms of the GNU General Public License as */ +/* published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config_xor.h" + +#undef FIL__ +#define FIL__ _("sh_subuid.c") + + +#include <sys/types.h> +#include <time.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <stdlib.h> +#include <errno.h> +#include <limits.h> + +#if defined(__linux__) + +#include "samhain.h" +#include "sh_unix.h" + +#define SH_SUBUID_FILE _("/etc/subuid") +#define SH_SUBGID_FILE _("/etc/subgid") + +struct subuid_t { + char name[32]; + unsigned long first; + unsigned long last; + struct subuid_t * next; +}; + +static time_t last_subuid = 0; +static time_t last_subgid = 0; + +struct subuid_t * list_subuid = NULL; +struct subuid_t * list_subgid = NULL; + +/* Check whether we need to re-read the subuid/subgid file + */ +static int needs_reread (char * file, time_t * last) +{ + int retval = S_FALSE; + struct stat buf; + int status = retry_lstat (FIL__, __LINE__, file, &buf); + + if (status == 0) + { + if ((buf.st_mtime - *last) > 1) + { + *last = buf.st_mtime; + retval = S_TRUE; + } + } + else if (status && errno == ENOENT) + { + /* If there was a file make sure we attempt to re-read + * to zero out the list. + */ + if (*last > 0) retval = S_TRUE; + *last = 0; + } + return retval; +} + +/* free the whole list + */ +static void free_subordinate(struct subuid_t * head) +{ + struct subuid_t * prev; + struct subuid_t * curr = head; + + while (curr) + { + prev = curr; + curr = curr->next; + SH_FREE(prev); + } + return; +} + +#define NFIELDS_SUBUID 3 + +static int get_ulong(char * str, unsigned long * result) +{ + char * endptr; + + errno = 0; + *result = strtoul(str, &endptr, 0); + if (*str != '\0' && *endptr == '\0' && errno != ERANGE) + return S_TRUE; + return S_FALSE; +} + +/* Parse a single line into name / startuid / lastuid + */ +static struct subuid_t * parse_subordinate(char * line) +{ + unsigned int nfields = NFIELDS_SUBUID; + size_t lengths[NFIELDS_SUBUID]; + unsigned long start, count; + struct subuid_t * new; + + char ** array = split_array(line, &nfields, ':', lengths); + + if (nfields != NFIELDS_SUBUID) + { SH_FREE(array); return NULL; } + + if (S_TRUE != get_ulong(array[1], &start)) + { SH_FREE(array); return NULL; } + if ((S_TRUE != get_ulong(array[2], &count)) || (count == 0)) + { SH_FREE(array); return NULL; } + if (lengths[0] == 0) + { SH_FREE(array); return NULL; } + + /* we have checked that count != 0 */ + --count; + + if (start > (ULONG_MAX - count)) + { SH_FREE(array); return NULL; } + + new = SH_ALLOC(sizeof(struct subuid_t)); + sl_strlcpy(new->name, array[0], 32); + new->first = start; + new->last = start + count; /* start+count-1, but we already did --count */ + new->next = NULL; + + SH_FREE(array); + return new; +} + +/* (re-)read the subuid/subgid file + */ +static void reread_subordinate (char * file, struct subuid_t ** head_ref) +{ + SL_TICKET fd = (-1); + char line[1024]; + + if (*head_ref) { free_subordinate(*head_ref); *head_ref = NULL; } + + fd = sl_open_read (FIL__, __LINE__, file, SL_YESPRIV); + if (!SL_ISERROR(fd)) + { + while ( sh_unix_getline(fd, line, sizeof(line)) > 0 ) + { + /* for invalid lines, NULL will be returned + */ + struct subuid_t * new = parse_subordinate(line); + + if (new) + { + new->next = *head_ref; + *head_ref = new; + } + } + sl_close(fd); + } + return; +} + +/* Return the username for a given subuid/subgid + */ +static char * get_name4id (unsigned long id, struct subuid_t * head) +{ + struct subuid_t * cur = head; + + while (cur) + { + if (id >= cur->first && id <= cur->last) + return cur->name; + cur = cur->next; + } + return NULL; +} + +/*********************************************** + * + * Public functions + * + ***********************************************/ + +/* Returns username or NULL for a subuid + */ +char * sh_get_subuid (unsigned long subuid) +{ + static int init = 0; + static char file[256]; + + if (!init) { sl_strlcpy(file, SH_SUBUID_FILE, sizeof(file)); init = 1; } + + if (S_TRUE == needs_reread(file, &last_subuid)) + reread_subordinate(file, &list_subuid); + + return get_name4id (subuid, list_subuid); +} + +/* Returns group name or NULL for subgid + */ +char * sh_get_subgid (unsigned long subgid) +{ + static int init = 0; + static char file[256]; + + if (!init) { sl_strlcpy(file, SH_SUBGID_FILE, sizeof(file)); init = 1; } + + if (S_TRUE == needs_reread(file, &last_subgid)) + reread_subordinate(file, &list_subgid); + + return get_name4id (subgid, list_subgid); +} + +/* Not Linux, hence no sub(u|g)id + */ +#else + +char * sh_get_subuid (unsigned long subuid) +{ + (void) subuid; + return NULL; +} + +char * sh_get_subgid (unsigned long subgid) +{ + (void) subgid; + return NULL; +} + +#endif diff --git a/src/sh_suidchk.c b/src/sh_suidchk.c index d9cc1f9..30c397c 100644 --- a/src/sh_suidchk.c +++ b/src/sh_suidchk.c @@ -996,8 +996,8 @@ static void report_file (const char * tmpcat, file_type * theFile, * putting it into a register, and avoids the 'clobbered * by longjmp' warning. And no, 'volatile' proved insufficient. */ -static void * sh_dummy_dirlist = NULL; -static void * sh_dummy_itmp = NULL; +void * sh_dummy_idirlist = NULL; +void * sh_dummy_itmp = NULL; static @@ -1027,8 +1027,8 @@ int sh_suidchk_check_internal (char * iname) /* Take the address to keep gcc from putting it into a register. * Avoids the 'clobbered by longjmp' warning. */ - sh_dummy_dirlist = (void*) &dirlist; - sh_dummy_itmp = (void*) &tmp; + sh_dummy_idirlist = (void*) &dirlist; + sh_dummy_itmp = (void*) &tmp; if (iname == NULL) { @@ -1145,7 +1145,7 @@ int sh_suidchk_check_internal (char * iname) (void) retry_msleep((int)((FileLimTotal/(FileLimNow-FileLimStart))/ ShSuidchkFps) , 0); } - + status = (int) retry_lstat(FIL__, __LINE__, tmpcat, &buf); if (status != 0) @@ -1185,6 +1185,7 @@ int sh_suidchk_check_internal (char * iname) /* fs is a STATIC string or NULL */ fs = filesystem_type (tmpcat, tmpcat, &buf); + if (fs != NULL #ifndef SH_SUIDTESTDIR && @@ -1301,6 +1302,7 @@ int sh_suidchk_check_internal (char * iname) { /* Running init. Report on files detected. */ + sh_dbIO_rootfs_strip(theFile->fullpath); sh_dbIO_data_write (theFile, fileHash); /* no call to sh_error_handle */ SH_MUTEX_LOCK(mutex_thread_nolog); sh_error_handle ((-1), FIL__, __LINE__, @@ -2210,6 +2212,7 @@ filesystem_type (char * path, char * relpath, struct stat * statp) } current_dev = statp->st_dev; current_fstype = filesystem_type_uncached (path, relpath, statp); + return current_fstype; } @@ -2231,7 +2234,7 @@ filesystem_type_uncached (path, relpath, statp) static char my_tmp_type[64]; #endif -#ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ +#ifdef FSTYPE_MNTENT /* 4.3BSD, SunOS, HP-UX, Dynix, Irix,Linux */ char *table = MOUNTED; FILE *mfp; struct mntent *mnt; @@ -2293,12 +2296,14 @@ filesystem_type_uncached (path, relpath, statp) char errmsg[256]; volatile int elevel = SH_ERR_ERR; size_t tlen = strlen(mnt->mnt_dir); - + if (tlen >= 6 && 0 == strcmp(&((mnt->mnt_dir)[tlen-6]), _("/.gvfs"))) elevel = SH_ERR_NOTICE; else if (tlen >= 5 && 0 == strcmp(&((mnt->mnt_dir)[tlen-5]), _("/gvfs"))) elevel = SH_ERR_NOTICE; - + else if (0 == strcmp (mnt->mnt_type, _("tracefs"))) + elevel = SH_ERR_NOTICE; + sl_snprintf(errmsg, sizeof(errmsg), _("stat(%s) failed"), mnt->mnt_dir); SH_MUTEX_LOCK(mutex_thread_nolog); @@ -2306,7 +2311,7 @@ filesystem_type_uncached (path, relpath, statp) errmsg, _("filesystem_type_uncached") ); SH_MUTEX_UNLOCK(mutex_thread_nolog); - return NULL; + continue; } dev = disk_stats.st_dev; } diff --git a/src/sh_tiger0.c b/src/sh_tiger0.c index aea8158..8a7ec17 100644 --- a/src/sh_tiger0.c +++ b/src/sh_tiger0.c @@ -378,7 +378,7 @@ sh_word32 * sh_tiger_hash_val (const char * filename, TigerType what, #ifdef TIGER_DBG ncount = 0; #endif - sl_memset(bbuf, 0, 56 ); + memset(bbuf, 0, 56 ); } #ifdef TIGER_DBG @@ -401,8 +401,8 @@ sh_word32 * sh_tiger_hash_val (const char * filename, TigerType what, tiger_dbg (res, 7, nblocks, ncount); #endif - sl_memset (bbuf, '\0', sizeof(bbuf)); - sl_memset (buffer, '\0', sizeof(buffer)); + memset (bbuf, 0, sizeof(bbuf)); + memset (buffer, 0, sizeof(buffer)); if (what == TIGER_FILE) (void) sl_close (fd); @@ -1020,8 +1020,8 @@ char * sh_tiger_md5_hash (char * filename, TigerType what, /*@-bufferoverflowhigh -usedef@*/ for (cnt = 0; cnt < 16; ++cnt) - sprintf (&outbuf[cnt*2], _("%02X"), /* known to fit */ - (unsigned int) md5buffer[cnt]); + sl_snprintf (&outbuf[cnt*2], 3, _("%02X"), /* known to fit */ + (unsigned int) md5buffer[cnt]); /*@+bufferoverflowhigh +usedef@*/ for (cnt = 32; cnt < KEY_LEN; ++cnt) outbuf[cnt] = '0'; @@ -1584,7 +1584,7 @@ static char * sh_tiger_sha1_hash (char * filename, TigerType what, /*@-bufferoverflowhigh -usedef@*/ for (cnt = 0; cnt < 20; ++cnt) - sprintf (&outbuf[cnt*2], _("%02X"), /* known to fit */ + sl_snprintf (&outbuf[cnt*2], 3, _("%02X"), /* known to fit */ (unsigned int) sha1buffer[cnt]); /*@+bufferoverflowhigh +usedef@*/ for (cnt = 40; cnt < KEY_LEN; ++cnt) diff --git a/src/sh_tiger1_64.c b/src/sh_tiger1_64.c index 9218d8a..d85a115 100644 --- a/src/sh_tiger1_64.c +++ b/src/sh_tiger1_64.c @@ -139,7 +139,7 @@ static /*volatile*/ const word64 XOR_CONST2=0x0123456789ABCDEFLL; #define roundend(a,b,c,x) \ : "+r" (a), "+r" (b), "+r" (c) \ - : "r" (a), "r" (b), "r" (c), "m" (x), "r" (&tiger_table),\ + : "g" (a), "g" (b), "g" (c), "m" (x), "r" (&tiger_table),\ "i" (MASK0), "i" (MASK8), "i" (MASK16), "r" (MASK32), "r" (MASK40), "r" (MASK48) \ : "3", "%rax","%rbx","%rcx","%rdx","%rsi", "%edi", "%r8" ); diff --git a/src/sh_tools.c b/src/sh_tools.c index 6485a58..09677b6 100644 --- a/src/sh_tools.c +++ b/src/sh_tools.c @@ -69,7 +69,7 @@ #define FD_SETSIZE 32 #endif #ifndef FD_ZERO -#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p))) +#define FD_ZERO(p) memset((char *)(p), 0, sizeof(*(p))) #endif @@ -134,7 +134,7 @@ int sh_tools_iface_is_present(char *str) struct addrinfo hints; int res; - memset (&hints, '\0', sizeof (hints)); + memset (&hints, 0, sizeof (hints)); hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; hints.ai_socktype = SOCK_STREAM; res = getaddrinfo (str, _("2543"), &hints, &ai); @@ -179,7 +179,7 @@ int sh_tools_iface_is_present(char *str) struct sockaddr_in sin; int sd; - memset(&sin, '\0', sizeof(sin)); + memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; if (inet_aton(str, &(sin.sin_addr))) { @@ -187,6 +187,7 @@ int sh_tools_iface_is_present(char *str) if (-1 == (sd = socket(AF_INET, SOCK_STREAM, 0))) { + /* cppcheck-suppress resourceLeak */ return 0; } @@ -863,6 +864,7 @@ int connect_port (char * address, int port, { if (tools_debug) fputs(_("-03- cached\n"), stderr); + /* cppcheck-suppress uninitStructMember */ fd = socket(ss.ss_family, SOCK_STREAM, 0); if (fd < 0) { @@ -878,8 +880,9 @@ int connect_port (char * address, int port, if (fail != (-1)) { + /* cppcheck-suppress uninitStructMember */ int addrlen = SH_SS_LEN(ss); - + if ( retry_connect(FIL__, __LINE__, fd, sh_ipvx_sockaddr_cast(&ss), addrlen) < 0) { @@ -911,7 +914,7 @@ int connect_port (char * address, int port, if (tools_debug) fputs(_("-03- not cached\n"), stderr); - memset (&hints, '\0', sizeof (hints)); + memset (&hints, 0, sizeof (hints)); hints.ai_flags = AI_ADDRCONFIG; #if defined(AI_CANONNAME) hints.ai_flags |= AI_CANONNAME; @@ -1382,6 +1385,7 @@ void sh_tools_probe_reset() return; } +#ifdef SH_ENCRYPT static int probe_ok(int flag) { (void) flag; @@ -1389,6 +1393,7 @@ static int probe_ok(int flag) return S_TRUE; return S_FALSE; } +#endif static unsigned char probe_header_set(unsigned char protocol) { @@ -1440,6 +1445,7 @@ unsigned char sh_tools_probe_store(unsigned char protocol, int * probe_flag) return protocol; } +#ifdef SH_ENCRYPT static int probe_ok(int flag) { if ((flag & SH_PROTO_IVA) != 0) @@ -1448,6 +1454,8 @@ static int probe_ok(int flag) } #endif +#endif + void get_header (unsigned char * head, unsigned long * bytes, char * u) { @@ -1664,10 +1672,10 @@ char * sh_tools_makePack (unsigned char * header, int flag, if ((i_blk*16) > payload_size && !oflow) { - memset(&full_ret[16+payload_size], '\0', (i_blk*16) - payload_size); + memset(&full_ret[16+payload_size], 0, (i_blk*16) - payload_size); payload_size = i_blk * 16; } - memset(&full_ret[16+payload_size], '\0', i_epad*16); + memset(&full_ret[16+payload_size], 0, i_epad*16); /* rewrite header */ @@ -2071,7 +2079,7 @@ char * get_client_uuid_file (const char * peer, unsigned long * length, const ch #endif -#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER) || defined(SH_STEALTH) || defined(WITH_GPG) || defined(WITH_PGP) +#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER) || defined(SH_STEALTH) || defined(WITH_SIG) /* --------- secure temporary file ------------ */ diff --git a/src/sh_unix.c b/src/sh_unix.c index c383bef..bb08dc2 100644 --- a/src/sh_unix.c +++ b/src/sh_unix.c @@ -82,7 +82,7 @@ #define FD_SETSIZE 32 #endif #ifndef FD_ZERO -#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p))) +#define FD_ZERO(p) memset((char *)(p), 0, sizeof(*(p))) #endif @@ -513,7 +513,7 @@ void sh_unix_sigexit (int mysignal) { ++immediate_exit_normal; if ((skey != NULL) && (immediate_exit_normal == 2)) - memset (skey, '\0', sizeof(sh_key_t)); + memset (skey, 0, sizeof(sh_key_t)); if (immediate_exit_normal == 2) { int val_return; @@ -578,7 +578,7 @@ void sh_unix_sigexit_fast (int mysignal) #if !defined(SL_DEBUG) || (!defined(USE_SYSTEM_MALLOC) && defined(USE_MALLOC_LOCK)) ++immediate_exit_fast; if (skey != NULL && immediate_exit_fast < 2) - memset (skey, '\0', sizeof(sh_key_t)); + memset (skey, 0, sizeof(sh_key_t)); if (immediate_exit_fast < 2) safe_logger (mysignal, 0, NULL); raise(SIGKILL); @@ -590,7 +590,7 @@ void sh_unix_sigexit_fast (int mysignal) { ++immediate_exit_fast; if (skey != NULL) - memset (skey, '\0', sizeof(sh_key_t)); + memset (skey, 0, sizeof(sh_key_t)); close_ipc (); safe_logger (mysignal, 0, NULL); do { @@ -630,7 +630,7 @@ void sh_unix_sigexit_fast (int mysignal) sh.prg_name, sh_sig_msg); if (skey != NULL) - memset (skey, '\0', sizeof(sh_key_t)); + memset (skey, 0, sizeof(sh_key_t)); close_ipc (); do { @@ -1209,6 +1209,8 @@ int tf_trust_check (const char * file, int mode) int status; int level; uid_t ff_euid = (uid_t) -1; + uid_t baduid; + gid_t badgid; SL_ENTER(_("tf_trust_check")); @@ -1255,11 +1257,14 @@ int tf_trust_check (const char * file, int mode) else level = SH_ERR_ERR; - tmp = sh_util_safe_name (file); - p = sl_trust_errfile(); + tmp = sh_util_safe_name (file); + p = sh_util_strdup(sl_trust_errfile()); + baduid = sl_trust_baduid(); + badgid = sl_trust_badgid(); + if (p && *p != '\0') { - tmp2 = sh_util_safe_name (sl_trust_errfile()); + tmp2 = sh_util_safe_name (p); sh_error_handle(level, FIL__, __LINE__, status, MSG_E_TRUST2, sl_error_string(status), tmp, tmp2); SH_FREE(tmp2); @@ -1269,7 +1274,6 @@ int tf_trust_check (const char * file, int mode) sh_error_handle(level, FIL__, __LINE__, status, MSG_E_TRUST1, sl_error_string(status), tmp); } - SH_FREE(tmp); if (status == SL_EBADUID || status == SL_EBADGID || status == SL_EBADOTH || status == SL_ETRUNC || @@ -1281,43 +1285,37 @@ int tf_trust_check (const char * file, int mode) _("An internal error occured in the trustfile function.\n")); break; case SL_ETRUNC: - tmp = sh_util_safe_name (file); dlog(1, FIL__, __LINE__, _("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"), tmp); - SH_FREE(tmp); break; case SL_EBADOTH: - tmp = sh_util_safe_name (file); - p = sl_trust_errfile(); dlog(1, FIL__, __LINE__, _("The path element: %s\nin the filename: %s is world writeable.\n"), - p, tmp); - SH_FREE(tmp); + (p) ? p : _("(null)"), tmp); break; case SL_EBADUID: - tmp = sh_util_safe_name (file); - p = sl_trust_errfile(); dlog(1, FIL__, __LINE__, _("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"), - (UID_CAST)sl_trust_baduid(), p, tmp); - SH_FREE(tmp); + (UID_CAST)baduid, (p) ? p : _("(null)"), tmp); break; case SL_EBADGID: - tmp = sh_util_safe_name (file); - p = sl_trust_errfile(); dlog(1, FIL__, __LINE__, _("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"), - p, tmp, (UID_CAST)sl_trust_badgid(), - (UID_CAST)sl_trust_baduid()); - SH_FREE(tmp); + (p) ? p : _("(null)"), tmp, (UID_CAST)badgid, + (UID_CAST)baduid); break; default: break; } - + SH_FREE(tmp); + if (p) SH_FREE(p); SL_RETURN((-1), _("tf_trust_check")); } + else { + SH_FREE(tmp); + if (p) SH_FREE(p); + } } SL_RETURN((0), _("tf_trust_check")); @@ -2342,11 +2340,11 @@ char * t_zone(const time_t * xx) diff = diff - (sign * 24 * 60); /* datum wrap-around correction */ hh = diff / 60; mm = diff - (hh * 60); - sprintf (tz, _("%+03d%02d"), hh, mm); /* known to fit */ + sl_snprintf (tz, sizeof(tz), _("%+03d%02d"), hh, mm); /* known to fit */ } else { - sprintf (tz, _("%+03d%02d"), 0, 0); + sl_snprintf (tz, sizeof(tz), _("%+03d%02d"), 0, 0); } SL_RETURN(tz, _("t_zone")); } @@ -2484,6 +2482,7 @@ char * sh_unix_time (time_t thetime, char * buffer, size_t len) sh_error_handle ((-1), FIL__, __LINE__, error_num, MSG_E_NET, errmsg, error_call, _("time"), sh.srvtime.name); + errflag = error_num; fail = 1; } @@ -2828,7 +2827,9 @@ static char * sh_userid_get (uid_t id, int which, char * out, size_t len) } /* --------- end caching code --------- */ - + +#include "sh_subuid.h" + char * sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len) { struct passwd * tempres; @@ -2864,21 +2865,10 @@ char * sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len) tempres = sh_getpwuid(uid); status = errno; #endif - - if (tempres == NULL) - { - sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL, - sh_error_message(status, errbuf, sizeof(errbuf)), - _("getpwuid"), (long) uid, _("completely missing")); -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) - SH_FREE(buffer); -#endif - sh_userid_add(uid, NULL, CACHE_UID); - SL_RETURN( NULL, _("sh_unix_getUIDname")); - } - - if (tempres->pw_name != NULL) + /* case 1: we have it + */ + if (tempres && tempres->pw_name != NULL) { sl_strlcpy(out, tempres->pw_name, len); @@ -2889,18 +2879,37 @@ char * sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len) #endif SL_RETURN( out, _("sh_unix_getUIDname")); - } - else + } + +#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) + SH_FREE(buffer); +#endif + + if (tempres == NULL) { + char * pwname = sh_get_subuid ((unsigned long) uid); + + if (pwname) + { + sl_strlcpy(out, pwname, len); + sh_userid_add(uid, out, CACHE_UID); + SL_RETURN( out, _("sh_unix_getUIDname")); + } + sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL, sh_error_message(status, errbuf, sizeof(errbuf)), - _("getpwuid"), (long) uid, _("pw_user")); -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) - SH_FREE(buffer); -#endif + _("getpwuid"), (long) uid, _("completely missing")); + sh_userid_add(uid, NULL, CACHE_UID); SL_RETURN( NULL, _("sh_unix_getUIDname")); } - /* notreached */ + + + /* getwpuid returns struct, but no pw_name + */ + sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_PWNULL, + sh_error_message(status, errbuf, sizeof(errbuf)), + _("getpwuid"), (long) uid, _("pw_user")); + SL_RETURN( NULL, _("sh_unix_getUIDname")); } char * sh_unix_getGIDname (int level, gid_t gid, char * out, size_t len) @@ -2960,21 +2969,7 @@ char * sh_unix_getGIDname (int level, gid_t gid, char * out, size_t len) SL_RETURN( NULL, _("sh_unix_getGIDname")); } - if (tempres == NULL) - { - sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_GRNULL, - sh_error_message(status, errbuf, sizeof(errbuf)), - _("getgrgid"), (long) gid, _("completely missing")); - -#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) - SH_FREE(buffer); -#endif - - sh_userid_add(gid, NULL, CACHE_GID); - SL_RETURN( NULL, _("sh_unix_getGIDname")); - } - - if (tempres->gr_name != NULL) + if (tempres && tempres->gr_name != NULL) { sl_strlcpy(out, tempres->gr_name, len); @@ -2986,19 +2981,33 @@ char * sh_unix_getGIDname (int level, gid_t gid, char * out, size_t len) SL_RETURN( out, _("sh_unix_getGIDname")); } - else - { - sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_GRNULL, - sh_error_message(status, errbuf, sizeof(errbuf)), - _("getgrgid"), (long) gid, _("gr_name")); #if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_GETGRGID_R) - SH_FREE(buffer); + SH_FREE(buffer); #endif + if (tempres == NULL) + { + char * grname = sh_get_subgid ((unsigned long) gid); + + if (grname) + { + sl_strlcpy(out, grname, len); + sh_userid_add((uid_t)gid, out, CACHE_GID); + SL_RETURN( out, _("sh_unix_getGIDname")); + } + + sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_GRNULL, + sh_error_message(status, errbuf, sizeof(errbuf)), + _("getgrgid"), (long) gid, _("completely missing")); + sh_userid_add(gid, NULL, CACHE_GID); SL_RETURN( NULL, _("sh_unix_getGIDname")); } - /* notreached */ + + sh_error_handle (level, FIL__, __LINE__, EINVAL, MSG_E_GRNULL, + sh_error_message(status, errbuf, sizeof(errbuf)), + _("getgrgid"), (long) gid, _("gr_name")); + SL_RETURN( NULL, _("sh_unix_getGIDname")); } int sh_unix_getUser () @@ -3067,7 +3076,7 @@ int sh_unix_getUser () /* notreached */ } - +/* return >0 on success, -1 on EOF */ int sh_unix_getline (SL_TICKET fd, char * line, int sizeofline) { register int count; @@ -3593,8 +3602,10 @@ int sh_check_rotated_log (const char * path, retval = S_TRUE; } } - SH_FREE(rotated_file); } + if (rotated_file) { + SH_FREE(rotated_file); + } } return retval; } @@ -3793,8 +3804,8 @@ int sh_unix_setcheckacl (const char * c) static void * sh_dummy_filename; -static void * sh_dummy_tmp; -static void * sh_dummy_tmp2; +void * sh_dummy_tmp; +void * sh_dummy_tmp2; int sh_unix_getinfo (int level, const char * filename, file_type * theFile, char * fileHash, int policy) @@ -3894,6 +3905,7 @@ int sh_unix_getinfo (int level, const char * filename, file_type * theFile, if (errno == EBADF && try == 0) /* obsolete, but we keep this, just in case */ { + /* cppcheck-suppress syntaxError */ ++try; goto try_again; } @@ -4593,7 +4605,7 @@ int sh_unix_lock (char * lockfile, char * flag) SL_ENTER(_("sh_unix_lock")); - sprintf (myPid, "%ld\n", (long) sh.pid); /* known to fit */ + sl_snprintf (myPid, sizeof(myPid), "%ld\n", (long) sh.pid); /* known to fit */ if (flag == NULL) /* PID file, check for directory */ { @@ -4861,8 +4873,8 @@ int sh_unix_file_exists(char * path) if (0 == retry_lstat(FIL__, __LINE__, path, &buf)) SL_RETURN( S_TRUE, _("sh_unix_file_exists")); - else - SL_RETURN( S_FALSE, _("sh_unix_file_exists")); + + SL_RETURN( S_FALSE, _("sh_unix_file_exists")); } @@ -4877,10 +4889,10 @@ int sh_unix_device_readable(int fd) if (retry_fstat(FIL__, __LINE__, fd, &buf) == -1) SL_RETURN( (-1), _("sh_unix_device_readable")); - else if ( S_ISCHR(buf.st_mode) && 0 != (S_IROTH & buf.st_mode) ) + if ( S_ISCHR(buf.st_mode) && 0 != (S_IROTH & buf.st_mode) ) SL_RETURN( (0), _("sh_unix_device_readable")); - else - SL_RETURN( (-1), _("sh_unix_device_readable")); + + SL_RETURN( (-1), _("sh_unix_device_readable")); } static char preq[16]; @@ -5397,6 +5409,7 @@ unsigned long first_hex_block(SL_TICKET fd, unsigned long * max); int sh_unix_getline_stealth (SL_TICKET fd, char * str, int len) { int add_off = 0, llen; + unsigned long bread; static unsigned long off_data = 0; static unsigned long max_data = 0; static unsigned long bytes_read = 0; @@ -5444,8 +5457,13 @@ int sh_unix_getline_stealth (SL_TICKET fd, char * str, int len) /* --- Read one line. --- */ - add_off = hideout_hex_block(fd, (unsigned char *) str, len, &bytes_read); - off_data += add_off; + add_off = hideout_hex_block(fd, (unsigned char *) str, len, &bread); + if (add_off > 0) + off_data += add_off; + bytes_read += bread; + + if (bread == 0 || add_off <= 0) /* EOF */ + str[0] = '\0'; llen = sl_strlen(str); SL_RETURN(llen, _("sh_unix_getline_stealth")); @@ -5467,6 +5485,8 @@ int hideout_hex_block(SL_TICKET fd, unsigned char * str, int len, ASSERT_RET((len > 1), _("len > 1"), (0)); + str[0] = '\0'; + *bytes_read = 0; --len; i = 0; @@ -5484,14 +5504,17 @@ int hideout_hex_block(SL_TICKET fd, unsigned char * str, int len, c = ' '; do { do { + errno = 0; num = sl_read (fd, &c, 1); } while (num == 0 && errno == EINTR); if (num > 0) ++here; - else if (num == 0) - SL_RETURN((0), _("hideout_hex_block")); - else + else if (num == 0) { SL_RETURN((-1), _("hideout_hex_block")); + } + else { + SL_RETURN((-1), _("hideout_hex_block")); + } } while (c == '\n' || c == '\t' || c == '\r' || c == ' '); } @@ -5513,8 +5536,10 @@ int hideout_hex_block(SL_TICKET fd, unsigned char * str, int len, if (i != 0) str[i] = '\0'; - else + else if (str[0] == '\n') str[i+1] = '\0'; /* keep newline and terminate */ + else + str[0] = '\0'; retval += here; *bytes_read += (bread/8); diff --git a/src/sh_utils.c b/src/sh_utils.c index 4a162c2..204b131 100644 --- a/src/sh_utils.c +++ b/src/sh_utils.c @@ -826,12 +826,14 @@ static char * sh_util_hmac_tiger (char * hexkey, for (i = 0; i < (KEY_LEN/8); ++i) copy_four ( (unsigned char *) &(cc[i]), h1[i]); + /* cppcheck-suppress uninitvar */ h2 = sh_tiger_hash_uint32 ( inner, TIGER_DATA, (unsigned long) KEY_BLOCK+textlen, kbuf, KEY_BYT/sizeof(UINT32)); for (i = KEY_LEN/8; i < (KEY_LEN/4); ++i) copy_four ( (unsigned char *) &(cc[i]), h2[i - (KEY_LEN/8)]); + /* cppcheck-suppress uninitvar */ SH_FREE(inner); (void) sh_tiger_hash ((char *) &cc[0], @@ -1087,7 +1089,7 @@ UINT32 taus_get () res_num = 1; SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); - memset(taus_svec, '\0', TAUS_SAMPLE * sizeof(UINT32)); + memset(taus_svec, 0, TAUS_SAMPLE * sizeof(UINT32)); return retval; } @@ -1243,9 +1245,10 @@ int sh_util_set_newkey (const char * new_in) return -1; } - if (NULL == (new = calloc(1,strlen(new_in) + 1))) + len = strlen(new_in) + 1; + if (NULL == (new = calloc(1, len))) goto bail_mem; - sl_strncpy(new, new_in, strlen(new_in) + 1); + memcpy(new, new_in, len); key = new; len = strlen(new); @@ -2200,6 +2203,7 @@ char * sh_util_strconcat (const char * arg1, ...) else SL_RETURN(NULL, _("sh_util_strconcat")); + /* cppcheck-suppress uninitvar */ strnew[0] = '\0'; (void) sl_strlcpy (strnew, arg1, length + 2); diff --git a/src/sh_utmp.c b/src/sh_utmp.c index 5c72209..444779b 100644 --- a/src/sh_utmp.c +++ b/src/sh_utmp.c @@ -140,41 +140,30 @@ SH_MUTEX_EXTERN(mutex_thread_nolog); #ifdef HAVE_UTMPX_H -#ifndef _PATH_UTMP -#ifdef UTMPX_FILE -#define _PATH_UTMP UTMPX_FILE -#else -#error You must define UTMPX_FILE in the file config.h -#endif -#endif -#ifndef _PATH_WTMP -#ifdef WTMPX_FILE -#define _PATH_WTMP WTMPX_FILE +#if defined(_PATH_UTMPX) +#define SH_PATH_UTMP _PATH_UTMPX +#elif defined(UTMPX_FILE) +#define SH_PATH_UTMP UTMPX_FILE +#elif defined(_PATH_UTMP) +#define SH_PATH_UTMP _PATH_UTMP #else -#error You must define WTMPX_FILE in the file config.h -#endif +#error You must define UTMPX_FILE in the file config.h #endif #else -#ifndef _PATH_UTMP -#ifdef UTMP_FILE -#define _PATH_UTMP UTMP_FILE +#if defined(_PATH_UTMP) +#define SH_PATH_UTMP _PATH_UTMP +#elif defined(UTMP_FILE) +#define SH_PATH_UTMP UTMP_FILE #else #error You must define UTMP_FILE in the file config.h #endif -#endif -#ifndef _PATH_WTMP -#ifdef WTMP_FILE -#define _PATH_WTMP WTMP_FILE -#else -#error You must define WTMP_FILE in the file config.h -#endif -#endif #endif typedef struct log_user { + time_t last_checked; char ut_tty[UT_LINESIZE+1]; char name[UT_NAMESIZE+1]; char ut_host[UT_HOSTSIZE+1]; @@ -183,18 +172,12 @@ typedef struct log_user { struct log_user * next; } blah_utmp; -#ifdef HAVE_UTTYPE -static char terminated_line[UT_HOSTSIZE]; -#endif - -static char * mode_path[] = { _PATH_WTMP, _PATH_WTMP, _PATH_UTMP }; - -static struct SH_UTMP_S save_utmp; +static char * utmp_path = SH_PATH_UTMP; static void sh_utmp_logout_morechecks(struct log_user * user); static void sh_utmp_login_morechecks(struct SH_UTMP_S * ut); -static void sh_utmp_addlogin (struct SH_UTMP_S * ut); -static void sh_utmp_check_internal(int mode); +static void sh_utmp_checklogin (struct SH_UTMP_S * ut, time_t start_read); +static void sh_utmp_check_internal(); static int ShUtmpLoginSolo = SH_ERR_INFO; static int ShUtmpLoginMulti = SH_ERR_WARN; @@ -257,12 +240,18 @@ static void set_defaults(void) return; } +#if defined(HAVE_UTMPX_H) && defined(HAVE_GETUTXENT) +#define USE_SETUTENT 1 +#elif defined(HAVE_GETUTENT) +#define USE_SETUTENT 1 +#endif -#if defined (HAVE_SETUTENT) && defined (USE_SETUTENT) -#ifdef HAVE_UTMPX_H +#if defined (USE_SETUTENT) -#define sh_utmp_utmpname utmpxname +#ifdef HAVE_UTMPX_H + +#define sh_utmp_utmpname(a) (void)(a) #define sh_utmp_setutent setutxent #define sh_utmp_endutent endutxent #define sh_utmp_getutent getutxent @@ -291,12 +280,8 @@ static void set_defaults(void) */ static FILE * sh_utmpfile = NULL; -static char sh_utmppath[80] = _PATH_UTMP; +static char sh_utmppath[80] = SH_PATH_UTMP; -/* sh_utmp_feed_forward is for optimizing - * (fseek instead of getutent loop) - */ -static long sh_utmp_feed_forward = 0; static void sh_utmp_utmpname(const char * str) { @@ -307,7 +292,7 @@ static void sh_utmp_utmpname(const char * str) sh_utmpfile = NULL; } - (void) sl_strlcpy (sh_utmppath, str, 80); + (void) sl_strlcpy (sh_utmppath, str, sizeof(sh_utmppath)); SL_RET0(_("sh_utmp_utmpname")); } @@ -343,11 +328,6 @@ static void sh_utmp_setutent(void) } } (void) fseek (sh_utmpfile, 0L, SEEK_SET); - if (-1 == fseek (sh_utmpfile, sh_utmp_feed_forward, SEEK_CUR)) - { - sh_utmp_feed_forward = 0; /* modified Apr 4, 2004 */ - (void) fseek (sh_utmpfile, 0L, SEEK_SET); - } clearerr (sh_utmpfile); SL_RET0(_("sh_utmp_setutent")); } @@ -387,63 +367,6 @@ static struct SH_UTMP_S * sh_utmp_getutent(void) SL_RETURN(&out, _("sh_utmp_getutent")); } -#ifdef USE_UNUSED - -static struct SH_UTMP_S * sh_utmp_getutline(struct SH_UTMP_S * ut) -{ - struct SH_UTMP_S * out; - - while (1) { - if ((out = sh_utmp_getutent()) == NULL) { - return NULL; - } -#ifdef HAVE_UTTYPE - if (out->ut_type == USER_PROCESS || out->ut_type == LOGIN_PROCESS) - if (sl_strcmp(ut->ut_line, out->ut_line) == 0) - return out; -#else - if ( 0 != sl_strncmp (out->ut_name, "reboot", 6) && - 0 != sl_strncmp (out->ut_name, "shutdown", 8) && - 0 != sl_strncmp (out->ut_name, "date", 4) ) - return out; -#endif - } - return NULL; -} - -static struct SH_UTMP_S * sh_utmp_getutid(struct SH_UTMP_S * ut) -{ -#ifdef HAVE_UTTYPE - struct SH_UTMP_S * out; - - if (ut->ut_type == RUN_LVL || ut->ut_type == BOOT_TIME || - ut->ut_type == NEW_TIME || ut->ut_type == OLD_TIME) - { - while (1) { - if ((out = sh_utmp_getutent()) == NULL) { - return NULL; - } - if (out->ut_type == ut->ut_type) - return out; - } - } - else if (ut->ut_type == INIT_PROCESS || ut->ut_type == LOGIN_PROCESS || - ut->ut_type == USER_PROCESS || ut->ut_type == DEAD_PROCESS ) - { - while (1) { - if ((out = sh_utmp_getutent()) == NULL) { - return NULL; - } - if (sl_strcmp(ut->ut_id, out->ut_id) == 0) - return out; - } - } -#endif - return NULL; -} -/* #ifdef USE_UNUSED */ -#endif - /* #ifdef HAVE_SETUTENT */ #endif @@ -510,9 +433,7 @@ static int sh_utmp_init_internal (void) } lastcheck = time (NULL); userlist = NULL; - memset (&save_utmp, 0, sizeof(struct SH_UTMP_S)); - sh_utmp_check_internal (2); /* current logins */ - sh_utmp_check_internal (0); + sh_utmp_check_internal (); /* current logins */ init_done = 1; SL_RETURN( (0), _("sh_utmp_init")); } @@ -617,7 +538,7 @@ int sh_utmp_timer (time_t tcurrent) if ( (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE) && sh.flag.checkSum != SH_CHECK_INIT ) { - sh_inotify_wait_for_change(mode_path[1], &inotify_watch, + sh_inotify_wait_for_change(utmp_path, &inotify_watch, &errnum, ShUtmpInterval); } @@ -656,7 +577,7 @@ int sh_utmp_check () SH_MUTEX_LOCK(mutex_thread_nolog); sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_UT_CHECK); SH_MUTEX_UNLOCK(mutex_thread_nolog); - sh_utmp_check_internal (1); + sh_utmp_check_internal (); SL_RETURN(0, _("sh_utmp_check")); } @@ -736,7 +657,7 @@ int sh_utmp_set_login_activate (const char * c) SL_RETURN(i, _("sh_utmp_set_login_activate")); } -#ifdef HAVE_UTTYPE + struct login_ct { char name[UT_NAMESIZE+1]; int nlogin; @@ -816,7 +737,6 @@ static int sh_utmp_login_r(char * str) return 0; } -#endif /* for each login: @@ -825,14 +745,14 @@ static int sh_utmp_login_r(char * str) * - link user.ut_record -> log_record */ -#ifdef HAVE_UTTYPE +#include <ctype.h> static int sh_utmp_is_virtual (char * in_utline, char * in_uthost) { if (in_uthost != NULL && in_utline != NULL && in_uthost[0] == ':' && - in_uthost[1] == '0' && + isdigit((int) in_uthost[1]) && 0 == sl_strncmp(in_utline, _("pts/"), 4)) { return 1; @@ -840,7 +760,139 @@ static int sh_utmp_is_virtual (char * in_utline, char * in_uthost) return 0; } + + +static void sh_utmp_log_out(int sev, struct log_user * user, int n) +{ + char ttt[TIM_MAX]; + + SH_MUTEX_LOCK(mutex_thread_nolog); + (void) sh_unix_time (user->time, ttt, TIM_MAX); + sh_error_handle( sev, FIL__, __LINE__, 0, +#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) + MSG_UT_LG3X, +#elif defined(HAVE_UTHOST) + MSG_UT_LG3A, +#else + MSG_UT_LG3B, +#endif + user->name, + user->ut_tty, +#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) + user->ut_host, + user->ut_ship, +#elif defined(HAVE_UTHOST) + user->ut_host, +#endif + ttt, + n + ); + SH_MUTEX_UNLOCK(mutex_thread_nolog); +} + +static void sh_utmp_log_multi(int sev, struct log_user * user, int n) +{ + char ttt[TIM_MAX]; + + SH_MUTEX_LOCK(mutex_thread_nolog); + (void) sh_unix_time (user->time, ttt, TIM_MAX); + sh_error_handle( sev, FIL__, __LINE__, 0, +#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) + MSG_UT_LG2X, +#elif defined(HAVE_UTHOST) + MSG_UT_LG2A, +#else + MSG_UT_LG2B, +#endif + user->name, + user->ut_tty, +#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) + user->ut_host, + user->ut_ship, +#elif defined(HAVE_UTHOST) + user->ut_host, +#endif + ttt, + n + ); + SH_MUTEX_UNLOCK(mutex_thread_nolog); +} + +static void sh_utmp_log_one(int sev, struct log_user * user, int n) +{ + char ttt[TIM_MAX]; + + SH_MUTEX_LOCK(mutex_thread_nolog); + (void) sh_unix_time (user->time, ttt, TIM_MAX); + sh_error_handle( sev, FIL__, __LINE__, 0, +#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) + MSG_UT_LG1X, +#elif defined(HAVE_UTHOST) + MSG_UT_LG1A, +#else + MSG_UT_LG1B, +#endif + user->name, + user->ut_tty, +#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) + user->ut_host, + user->ut_ship, +#elif defined(HAVE_UTHOST) + user->ut_host, #endif + ttt, + n + ); + SH_MUTEX_UNLOCK(mutex_thread_nolog); +} + +static void sh_utmp_purge_old (time_t start_read) +{ + struct log_user * user = userlist; + struct log_user * userold = userlist; + volatile int status; + + /* ------- find old entries -------- + */ + while (user != NULL) + { + if (user->last_checked < start_read) + { + /* report logout */ + if (0 == sh_utmp_is_virtual(user->ut_tty, user->ut_host)) + { + /* reference count down on list of logged in users */ + status = sh_utmp_login_r(user->name); + + sh_utmp_log_out(ShUtmpLogout, user, status); + sh_utmp_logout_morechecks((struct log_user *)user); + } + + /* remove entry */ + if (userold == user && userold == userlist) + { + /* first element in userlist, advance userlist & userold */ + userold = user->next; + userlist = user->next; + SH_FREE((struct log_user *)user); + user = userlist; + } + else + { + /* other element in userlist, cut it out */ + userold->next = user->next; + SH_FREE((struct log_user *)user); + user = userold->next; + } + } + else + { + userold = user; + user = user->next; + } + } + return; +} /* These variables are not used anywhere. They only exist * to assign &userold, &user to them, which keeps gcc from @@ -851,33 +903,19 @@ void * sh_dummy_850_userold = NULL; void * sh_dummy_851_user = NULL; -static void sh_utmp_addlogin (struct SH_UTMP_S * ut) +static void sh_utmp_checklogin (struct SH_UTMP_S * ut, time_t start_read) { struct log_user * user = userlist; struct log_user * userold = userlist; -#ifdef HAVE_UTTYPE - struct log_user * username = userlist; -#endif - char ttt[TIM_MAX]; -#ifdef HAVE_UTTYPE + struct log_user * username = userlist; volatile int status; -#endif - SL_ENTER(_("sh_utmp_addlogin")); - if (ut->ut_line[0] == '\0') - SL_RET0(_("sh_utmp_addlogin")); + SL_ENTER(_("sh_utmp_checklogin")); - /* for some stupid reason, AIX repeats the wtmp entry for logouts - * with ssh - */ - if (memcmp (&save_utmp, ut, sizeof(struct SH_UTMP_S)) == 0) - { - memset(&save_utmp, (int) '\0', sizeof(struct SH_UTMP_S)); - SL_RET0(_("sh_utmp_addlogin")); - } - memcpy (&save_utmp, ut, sizeof(struct SH_UTMP_S)); + if (ut->ut_line[0] == '\0') + SL_RET0(_("sh_utmp_checklogin")); /* Take the address to keep gcc from putting them into registers. * Avoids the 'clobbered by longjmp' warning. @@ -889,273 +927,108 @@ static void sh_utmp_addlogin (struct SH_UTMP_S * ut) */ while (user != NULL) { - if (0 == sl_strncmp((char*)(user->ut_tty), ut->ut_line, UT_LINESIZE) ) + if (0 == sl_strncmp(user->ut_tty, ut->ut_line, UT_LINESIZE) && + 0 == sl_strncmp(user->name, ut->ut_name, UT_NAMESIZE)) break; userold = user; user = user->next; } -#ifdef HAVE_UTTYPE + while (username != NULL) { if (0 == sl_strncmp(username->name, ut->ut_name, UT_NAMESIZE) ) break; username = username->next; } -#endif + -#ifdef HAVE_UTTYPE - /* ---------- LOGIN -------------- */ - if (ut->ut_type == USER_PROCESS) + if (user == NULL) { - if (user == NULL) - { - user = SH_ALLOC(sizeof(struct log_user)); - user->next = userlist; - userlist = (struct log_user *) user; - } - (void) sl_strlcpy((char*)(user->ut_tty), ut->ut_line, UT_LINESIZE+1); - (void) sl_strlcpy((char*)(user->name), ut->ut_name, UT_NAMESIZE+1); -#ifdef HAVE_UTHOST - (void) sl_strlcpy((char*)(user->ut_host), ut->ut_host, UT_HOSTSIZE+1); -#else - user->ut_host[0] = '\0'; -#endif -#ifdef HAVE_UTADDR -#ifdef HAVE_UTADDR_V6 - my_inet_ntoa(ut->ut_addr_v6, user->ut_ship, SH_IP_BUF); -#else - my_inet_ntoa(ut->ut_addr, user->ut_ship, SH_IP_BUF); -#endif -#endif - user->time = ut->ut_time; - - if (username == NULL /* not yet logged in */ - || 0 == sl_strncmp(ut->ut_line, _("ttyp"), 4) /* in virt. console */ - || 0 == sl_strncmp(ut->ut_line, _("ttyq"), 4) /* in virt. console */ - ) { - status = sh_utmp_login_a((char*)user->name); - SH_MUTEX_LOCK(mutex_thread_nolog); - (void) sh_unix_time (user->time, ttt, TIM_MAX); - sh_error_handle( ShUtmpLoginSolo, FIL__, __LINE__, 0, -#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) - MSG_UT_LG1X, -#elif defined(HAVE_UTHOST) - MSG_UT_LG1A, -#else - MSG_UT_LG1B, -#endif - user->name, - user->ut_tty, -#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) - user->ut_host, - user->ut_ship, -#elif defined(HAVE_UTHOST) - user->ut_host, -#endif - ttt, - status - ); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - } else - if (0 == sh_utmp_is_virtual(ut->ut_line, (char*)user->ut_host)) - { - status = sh_utmp_login_a((char*)user->name); - SH_MUTEX_LOCK(mutex_thread_nolog); - (void) sh_unix_time (user->time, ttt, TIM_MAX); - sh_error_handle( ShUtmpLoginMulti, FIL__, __LINE__, 0, -#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) - MSG_UT_LG2X, -#elif defined(HAVE_UTHOST) - MSG_UT_LG2A, -#else - MSG_UT_LG2B, -#endif - user->name, - user->ut_tty, -#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) - user->ut_host, - user->ut_ship, -#elif defined(HAVE_UTHOST) - user->ut_host, -#endif - ttt, - status - ); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - } - - sh_utmp_login_morechecks(ut); + user = SH_ALLOC(sizeof(struct log_user)); + user->next = userlist; + userlist = (struct log_user *) user; + } + else if ( (user->time == ut->ut_time) && + 0 == sl_strcmp (user->name, ut->ut_name)) + { + /* we have it on record and nothing has changed */ + user->last_checked = start_read; goto out; } - - - /* --------- LOGOUT ---------------- */ - else if (ut->ut_name[0] == '\0' - || ut->ut_type == DEAD_PROCESS /* solaris does not clear ut_name */ - ) + else { - if (user != NULL) - { -#if defined(__linux__) - if (0 == sh_utmp_is_virtual(ut->ut_line, (char*)user->ut_host)) { -#endif - status = sh_utmp_login_r((char*)user->name); - SH_MUTEX_LOCK(mutex_thread_nolog); - (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX); - sh_error_handle( ShUtmpLogout, FIL__, __LINE__, 0, -#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) - MSG_UT_LG3X, -#elif defined(HAVE_UTHOST) - MSG_UT_LG3A, -#else - MSG_UT_LG3B, -#endif - user->name, - user->ut_tty, -#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) - user->ut_host, - user->ut_ship, -#elif defined(HAVE_UTHOST) - user->ut_host, -#endif - ttt, - status - ); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - userold->next = user->next; - if (user == userlist) - userlist = user->next; - sh_utmp_logout_morechecks((struct log_user *)user); - SH_FREE((struct log_user *)user); - user = NULL; -#if defined(__linux__) - } -#endif - } - else + /* we have it on record and something has changed */ + if (0 == sh_utmp_is_virtual(user->ut_tty, user->ut_host)) { - (void) sl_strlcpy(terminated_line, ut->ut_line, UT_HOSTSIZE); - SH_MUTEX_LOCK(mutex_thread_nolog); - (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX); - sh_error_handle( ShUtmpLogout, FIL__, __LINE__, 0, - MSG_UT_LG3C, - terminated_line, - ttt, 0 - ); - SH_MUTEX_UNLOCK(mutex_thread_nolog); + /* reference count down on list of logged in users */ + status = sh_utmp_login_r(user->name); + + sh_utmp_log_out(ShUtmpLogout, user, status); + sh_utmp_logout_morechecks((struct log_user *)user); } - goto out; } - /* default */ - goto out; - - /* #ifdef HAVE_UTTYPE */ -#else - - if (user == NULL) /* probably a login */ - { - user = SH_ALLOC(sizeof(struct log_user)); - sl_strlcpy(user->ut_tty, ut->ut_line, UT_LINESIZE+1); - sl_strlcpy(user->name, ut->ut_name, UT_NAMESIZE+1); + user->last_checked = start_read; + + (void) sl_strlcpy(user->ut_tty, ut->ut_line, UT_LINESIZE+1); + (void) sl_strlcpy(user->name, ut->ut_name, UT_NAMESIZE+1); #ifdef HAVE_UTHOST - sl_strlcpy(user->ut_host, ut->ut_host, UT_HOSTSIZE+1); + (void) sl_strlcpy(user->ut_host, ut->ut_host, UT_HOSTSIZE+1); +#else + user->ut_host[0] = '\0'; #endif #ifdef HAVE_UTADDR #ifdef HAVE_UTADDR_V6 - my_inet_ntoa(ut->ut_addr_v6, user->ut_ship, SH_IP_BUF); -#else - my_inet_ntoa(ut->ut_addr, user->ut_ship, SH_IP_BUF); -#endif -#endif - user->time = ut->ut_time; - user->next = userlist; - userlist = user; - - SH_MUTEX_LOCK(mutex_thread_nolog); - (void) sh_unix_time (user->time, ttt, TIM_MAX); - sh_error_handle( ShUtmpLoginSolo, FIL__, __LINE__, 0, -#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) - MSG_UT_LG1X, -#elif defined(HAVE_UTHOST) - MSG_UT_LG1A, + my_inet_ntoa(ut->ut_addr_v6, user->ut_ship, SH_IP_BUF); #else - MSG_UT_LG1B, + my_inet_ntoa(ut->ut_addr, user->ut_ship, SH_IP_BUF); #endif - user->name, - user->ut_tty, -#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) - user->ut_host, - user->ut_ship, -#elif defined(HAVE_UTHOST) - user->ut_host, #endif - ttt, - 1 - ); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - sh_utmp_login_morechecks(ut); + user->time = ut->ut_time; + + if (username == NULL) /* not yet logged in */ + { + /* add this username to the list of logged in users */ + status = sh_utmp_login_a(user->name); + + sh_utmp_log_one(ShUtmpLoginSolo, user, status); + } - else /* probably a logout */ + else if (0 == sh_utmp_is_virtual(user->ut_tty, (char*)user->ut_host)) { - SH_MUTEX_LOCK(mutex_thread_nolog); - (void) sh_unix_time (ut->ut_time, ttt, TIM_MAX); - sh_error_handle( ShUtmpLogout, FIL__, __LINE__, 0, -#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) - MSG_UT_LG2X, -#elif defined(HAVE_UTHOST) - MSG_UT_LG2A, -#else - MSG_UT_LG2B, -#endif - user->name, - user->ut_tty, -#if defined(HAVE_UTHOST) && defined(HAVE_UTADDR) - user->ut_host, - user->ut_ship, -#elif defined(HAVE_UTHOST) - user->ut_host, -#endif - ttt, - 1 - ); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - sh_utmp_logout_morechecks(user); - userold->next = user->next; - if (user == userlist) /* inserted Apr 4, 2004 */ - userlist = user->next; - SH_FREE(user); - user = NULL; + /* add this username to the list of logged in users */ + status = sh_utmp_login_a((char*)user->name); + + sh_utmp_log_multi(ShUtmpLoginMulti, user, status); } + sh_utmp_login_morechecks(ut); + goto out; -#endif out: sh_dummy_851_user = NULL; sh_dummy_850_userold = NULL; - SL_RET0(_("sh_utmp_addlogin")); + SL_RET0(_("sh_utmp_checklogin")); } static time_t lastmod = 0; -static off_t lastsize = 0; -static unsigned long lastread = 0; -static void sh_utmp_check_internal (int mode) +static void sh_utmp_check_internal () { struct stat buf; int error; struct SH_UTMP_S * ut; - unsigned long this_read; int val_retry; + time_t start_read; SL_ENTER(_("sh_utmp_check_internal")); /* error if no access */ do { - val_retry = /*@-unrecog@*/lstat ( mode_path[mode], &buf)/*@+unrecog@*/; + val_retry = /*@-unrecog@*/lstat ( utmp_path, &buf)/*@+unrecog@*/; } while (val_retry < 0 && errno == EINTR); if (0 != val_retry) @@ -1163,87 +1036,43 @@ static void sh_utmp_check_internal (int mode) error = errno; SH_MUTEX_LOCK(mutex_thread_nolog); sh_error_handle((-1), FIL__, __LINE__, error, MSG_E_ACCESS, - (long) sh.real.uid, mode_path[mode]); + (long) sh.real.uid, utmp_path); SH_MUTEX_UNLOCK(mutex_thread_nolog); SL_RET0(_("sh_utmp_check_internal")); } - /* modification time - */ - if (mode < 2) - { - if (/*@-usedef@*/buf.st_mtime <= lastmod/*@+usedef@*/) - { - SL_RET0(_("sh_utmp_check_internal")); - } - else - lastmod = buf.st_mtime; - } - - /* file size + /* check modification time */ - if (/*@-usedef@*/buf.st_size < lastsize/*@+usedef@*/ && mode < 2) + if (/*@-usedef@*/buf.st_mtime <= lastmod/*@+usedef@*/) { - SH_MUTEX_LOCK(mutex_thread_nolog); - sh_error_handle((-1), FIL__, __LINE__, 0, MSG_UT_ROT, - mode_path[mode]); - SH_MUTEX_UNLOCK(mutex_thread_nolog); - lastread = 0; -#ifndef USE_SETUTENT - sh_utmp_feed_forward = 0L; -#endif + SL_RET0(_("sh_utmp_check_internal")); } + else + lastmod = buf.st_mtime; - if (mode < 2) - lastsize = buf.st_size; - - if (buf.st_size == 0) - SL_RET0(_("sh_utmp_check_internal")); - - sh_utmp_utmpname(mode_path[mode]); + sh_utmp_utmpname(utmp_path); sh_utmp_setutent(); - /* - * feed forward if initializing - * we need to do this here - */ - this_read = 0; - - if (mode < 2) - { - while (this_read < lastread) { - (void) sh_utmp_getutent(); - ++this_read; - } - } - /* start reading */ - this_read = 0; + start_read = time(NULL); + while (1 == 1) { ut = sh_utmp_getutent(); if (ut == NULL) break; /* modified: ut_user --> ut_name */ - if (mode == 1 || (mode == 2 && ut->ut_name[0] != '\0' + if (ut->ut_name[0] != '\0' #ifdef HAVE_UTTYPE - && ut->ut_type != DEAD_PROCESS + && ut->ut_type == USER_PROCESS #endif - )) - sh_utmp_addlogin (ut); - ++this_read; + ) + sh_utmp_checklogin (ut, start_read); } sh_utmp_endutent(); - if (mode < 2) - { - lastread += this_read; -#ifndef USE_SETUTENT - sh_utmp_feed_forward += (long) (this_read * sizeof(struct SH_UTMP_S)); - lastread = 0; -#endif - } + sh_utmp_purge_old (start_read); SL_RET0(_("sh_utmp_check_internal")); } diff --git a/src/sh_xfer_client.c b/src/sh_xfer_client.c index abc6504..aa4941c 100644 --- a/src/sh_xfer_client.c +++ b/src/sh_xfer_client.c @@ -96,7 +96,7 @@ #define FD_SETSIZE 32 #endif #ifndef FD_ZERO -#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p))) +#define FD_ZERO(p) memset((char *)(p), 0, sizeof(*(p))) #endif #if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK) @@ -768,7 +768,7 @@ static int xfer_auth(int is_reinit, int * initialized, /* verify random nonce v from server H(v, P)v */ sh_passwd (nounce, NULL, NULL, temp); - if ( 0 != sl_strncmp(temp, answer, KEY_LEN)) + if ( 0 != sl_ts_strncmp(temp, answer, KEY_LEN)) flag_err = (-1); TPT(( 0, FIL__, __LINE__, _("msg=<c/r: vrfy nonce, flag_err = %d>\n"), @@ -1002,7 +1002,7 @@ static int xfer_auth(int is_reinit, int * initialized, M_buf, sizeof(M_buf) ); if (M != NULL && - 0 == sl_strncmp (answer, M, KEY_LEN+1)) + 0 == sl_ts_strncmp (answer, M, KEY_LEN+1)) { sl_strlcpy (skey->session, sh_tiger_hash(foo_Sc, @@ -1050,7 +1050,7 @@ static int xfer_auth(int is_reinit, int * initialized, { xfer_timeout_val *= 2; sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_NOAUTH); - memset(answer, '\0', 512); + memset(answer, 0, 512); MUNLOCK(answer, 512); SH_FREE(answer); return -1; @@ -1082,7 +1082,7 @@ int xfer_check_server_cmd(char * answer, char * buffer) (void) sl_strlcpy(buffer, &answer[KEY_LEN], pos+1); flag_err = - sl_strncmp(&answer[KEY_LEN+pos], + sl_ts_strncmp(&answer[KEY_LEN+pos], sh_util_siggen(skey->session, buffer, pos, @@ -1201,12 +1201,12 @@ int xfer_send_message(char * errmsg, int sockfd, char * answer) */ (void) sl_strlcpy(buffer, errmsg, len); (void) sl_strlcat(buffer, nsrv, len); - flag_err = sl_strncmp(answer, - sh_util_siggen(skey->session, - buffer, - sl_strlen(buffer), - sigbuf, sizeof(sigbuf)), - KEY_LEN); + flag_err = sl_ts_strncmp(answer, + sh_util_siggen(skey->session, + buffer, + sl_strlen(buffer), + sigbuf, sizeof(sigbuf)), + KEY_LEN); TPT((0, FIL__, __LINE__, _("msg=<sign %s.>\n"), sh_util_siggen(skey->session, buffer, sl_strlen(buffer), sigbuf, sizeof(sigbuf)))); diff --git a/src/sh_xfer_server.c b/src/sh_xfer_server.c index 0f7f1ab..fcc80fc 100644 --- a/src/sh_xfer_server.c +++ b/src/sh_xfer_server.c @@ -104,7 +104,7 @@ #define FD_SETSIZE 32 #endif #ifndef FD_ZERO -#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p))) +#define FD_ZERO(p) memset((char *)(p), 0, sizeof(*(p))) #endif #if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK) @@ -418,6 +418,11 @@ char * clt_stat[] = { * } client_t; */ +typedef struct client_alias { + char * alias; + char * hostname; +} alias_t; + #include "zAVLTree.h" static char * sh_tolower (char * s) @@ -434,7 +439,7 @@ static char * sh_tolower (char * s) } /* Function to return the key for indexing - * the argument + * the argument (for the client list) */ zAVLKey sh_avl_key (void const * arg) { @@ -444,6 +449,17 @@ zAVLKey sh_avl_key (void const * arg) zAVLTree * all_clients = NULL; +/* Function to return the key for indexing + * the argument (for the aliases list) + */ +zAVLKey sh_avl_alias (void const * arg) +{ + const alias_t * sa = (const alias_t *) arg; + return (zAVLKey) sa->alias; +} + +zAVLTree * all_aliases = NULL; + void sh_xfer_html_write() { SL_ENTER(_("sh_xfer_html_write")); @@ -469,7 +485,7 @@ int sh_xfer_use_clt_sev (const char * c) } -/* the destructor +/* the destructor (client list item) */ void free_client(void * inptr) { @@ -491,6 +507,100 @@ void free_client(void * inptr) SL_RET0(_("free_client")); } +/* the destructor (alias list item) + */ +void free_alias(void * inptr) +{ + alias_t * here; + + SL_ENTER(_("free_alias")); + if (inptr == NULL) + SL_RET0(_("free_alias")); + else + here = (alias_t *) inptr; + + if (here->alias != NULL) + SH_FREE(here->alias); + if (here->hostname != NULL) + SH_FREE(here->hostname); + SH_FREE(here); + SL_RET0(_("free_alias")); +} + +int sh_xfer_register_alias (const char * str) +{ + alias_t * newalias; + alias_t * testalias; + + const char * ptr; + int sepnum = 0; + int sep = 0; + register int i = 0; + int siz_str = 0; + + SL_ENTER(_("sh_xfer_register_alias")); + + ptr = str; + while (*ptr) { + if (*ptr == '@' && sepnum < 1) + { + sep = i; + ++sepnum; + } + ++ptr; ++i; + } + + if (all_aliases == NULL) + { + all_aliases = zAVLAllocTree (sh_avl_alias, zAVL_KEY_STRING); + if (all_aliases == NULL) + { + (void) safe_logger (0, 0, NULL); + aud__exit(FIL__, __LINE__, EXIT_FAILURE); + } + } + + if ((sepnum == 1) && (sep > 0) && (i > (sep + 1))) + { + newalias = SH_ALLOC (sizeof(alias_t)); + newalias->alias = SH_ALLOC (sep+1); + newalias->hostname = SH_ALLOC (sl_strlen(str)-sep); + + /* truncate */ + sl_strlcpy(newalias->alias, &str[0], sep+1); + sh_tolower(newalias->alias); + + /* truncate */ + sl_strlcpy(newalias->hostname, &str[sep+1], sl_strlen(str)-sep); + sh_tolower(newalias->hostname); + + testalias = (alias_t *) zAVLSearch (all_aliases, newalias->alias); + + if (testalias != NULL) + { + /* keep the alias but replace the hostname with the new one */ + SH_FREE(testalias->hostname); + siz_str = strlen (newalias->hostname) + 1; + testalias->hostname = SH_ALLOC (siz_str); + sl_strlcpy(testalias->hostname, newalias->hostname, siz_str); + + free_alias(newalias); + SL_RETURN( 0, _("sh_xfer_register_alias")); + } + else + { + if (0 == zAVLInsert (all_aliases, newalias)) + { + sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_AREG, + newalias->alias, + newalias->hostname); + SL_RETURN( 0, _("sh_xfer_register_alias")); + } + } + } + SL_RETURN (-1, _("sh_xfer_register_alias")); +} + int sh_xfer_register_client (const char * str) { @@ -1052,6 +1162,7 @@ int set_socket_peer (const char * c) */ client_t * search_register(sh_conn_t * conn, int pos) { + alias_t * this_alias; client_t * this_client; char peer_ip[SH_IP_BUF]; char numerical[SH_IP_BUF]; @@ -1067,6 +1178,7 @@ client_t * search_register(sh_conn_t * conn, int pos) { memcpy(&peer_addr, &(conn->addr_peer), sizeof(struct sh_sockaddr)); sh_ipvx_ntoa (peer_ip, sizeof(peer_ip), &peer_addr); + peer_name[0] = '\0'; /* get canonical name of socket peer */ @@ -1085,6 +1197,14 @@ client_t * search_register(sh_conn_t * conn, int pos) { sl_strlcpy(peer_name, peer_ip, MAXHOSTNAMELEN + 1); } + else + { + this_alias = zAVLSearch(all_aliases, peer_name); + if (this_alias) + { + sl_strlcpy(peer_name, this_alias->hostname, MAXHOSTNAMELEN + 1); + } + } search_string = peer_name; } @@ -1196,7 +1316,7 @@ client_t * do_check_client(sh_conn_t * conn, int * retval) sigbuf, sizeof(sigbuf)), KEY_LEN+1); - if (0 != sl_strncmp(conn->K, conn->buf, KEY_LEN)) + if (0 != sl_ts_strncmp(conn->K, conn->buf, KEY_LEN)) { TPT((0, FIL__, __LINE__, _("msg=<clt %s>\n"), conn->buf)); TPT((0, FIL__, __LINE__, _("msg=<srv %s>\n"), conn->K)); @@ -1228,11 +1348,6 @@ static void do_file_send_data(sh_conn_t * conn) char * send_buf; int bytes; SL_TICKET sfd = -1; -#ifdef SH_ENCRYPT - int blkfac; - int rem; - int send_bytes; -#endif if (conn == NULL || conn->FileName == NULL) { @@ -1279,26 +1394,11 @@ static void do_file_send_data(sh_conn_t * conn) if (bytes >= 0) { + send_buf = hash_me(conn->K, read_buf, bytes); #ifdef SH_ENCRYPT - /* need to send N * B_SIZ bytes - */ - blkfac = bytes / B_SIZ; - rem = bytes - (blkfac * B_SIZ); - if (rem != 0) - { - memset(&read_buf[bytes], '\n', (B_SIZ-rem)); - ++blkfac; - send_bytes = blkfac * B_SIZ; - } - else - send_bytes = bytes; - - send_buf = hash_me(conn->K, read_buf, send_bytes); - - sh_xfer_send_crypt (conn, send_buf, send_bytes+KEY_LEN, _("FILE"), + sh_xfer_send_crypt (conn, send_buf, bytes+KEY_LEN, _("FILE"), SH_PROTO_BIG|conn->client_entry->encf_flag); #else - send_buf = hash_me(conn->K, read_buf, bytes); sh_xfer_send_crypt (conn, send_buf, bytes+KEY_LEN, _("FILE"), SH_PROTO_BIG); #endif @@ -1662,12 +1762,12 @@ static int do_message_transfer(sh_conn_t * conn, int state) /* verify hash */ buffer = sh_util_strconcat(conn->buf, conn->challenge, NULL); - i = sl_strncmp(hash, - sh_util_siggen(conn->client_entry->session_key, - buffer, - sl_strlen(buffer), - sigbuf, sizeof(sigbuf)), - KEY_LEN); + i = sl_ts_strncmp(hash, + sh_util_siggen(conn->client_entry->session_key, + buffer, + sl_strlen(buffer), + sigbuf, sizeof(sigbuf)), + KEY_LEN); TPT((0, FIL__, __LINE__, _("msg=<sign %s.>\n"), sh_util_siggen(conn->client_entry->session_key, buffer, @@ -1787,7 +1887,7 @@ static int do_message_transfer(sh_conn_t * conn, int state) SH_FREE(ptok); clt_class = (-1); } - memset(buffer, '\0', sl_strlen(buffer)); + memset(buffer, 0, sl_strlen(buffer)); SH_FREE(buffer); /* SERVER CONF SEND @@ -1845,7 +1945,7 @@ static int do_message_transfer(sh_conn_t * conn, int state) SH_PROTO_MSG|SH_PROTO_END); #endif - memset(buffer, '\0', sl_strlen(buffer)); + memset(buffer, 0, sl_strlen(buffer)); SH_FREE(buffer); /* sh_xfer_do_free (conn); */ @@ -2086,7 +2186,7 @@ int do_auth(sh_conn_t * conn) TPT((0, FIL__, __LINE__, _("msg=<c/r: H = %s>\n"), hash)); TPT((0, FIL__, __LINE__, _("msg=<c/r: P = %s>\n"), conn->M1)); - if ( 0 != sl_strncmp(conn->M1, conn->buf, KEY_LEN)) + if ( 0 != sl_ts_strncmp(conn->M1, conn->buf, KEY_LEN)) { sh_error_handle((-1), FIL__, __LINE__, 0, MSG_TCP_BADCONN, _("Session key mismatch"), conn->peer); @@ -2412,7 +2512,7 @@ int do_auth(sh_conn_t * conn) * ----- send M2 = H(A, M1, K) ------- */ if (conn->buf != NULL && - sl_strncmp(conn->buf, conn->M1, KEY_LEN) == 0) + sl_ts_strncmp(conn->buf, conn->M1, KEY_LEN) == 0) { /* * send M2 @@ -2425,8 +2525,12 @@ int do_auth(sh_conn_t * conn) _("PARP"), (conn->head[0]|SH_PROTO_SRP)); - if (conn->A != NULL) SH_FREE(conn->A); conn->A = NULL; - if (conn->M1 != NULL) SH_FREE(conn->M1); conn->M1 = NULL; + if (conn->A != NULL) + SH_FREE(conn->A); + conn->A = NULL; + if (conn->M1 != NULL) + SH_FREE(conn->M1); + conn->M1 = NULL; sl_strlcpy(conn->client_entry->session_key, conn->K, KEY_LEN+1); TPT((0, FIL__, __LINE__, _("msg=<key %s>\n"), @@ -2449,7 +2553,9 @@ int do_auth(sh_conn_t * conn) _("sh_xfer_prep_send_int: makeKey")); #endif - if (conn->K != NULL) SH_FREE(conn->K); conn->K = NULL; + if (conn->K != NULL) + SH_FREE(conn->K); + conn->K = NULL; conn->client_entry->last_connect = time (NULL); @@ -3102,7 +3208,7 @@ int sh_create_tcp_socket (void) #if defined(USE_IPVX) if (use_server_interface == 0) /* INADDR_ANY, listen on all interfaces */ { - memset (&hints, '\0', sizeof (hints)); + memset (&hints, 0, sizeof (hints)); hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; @@ -3387,6 +3493,10 @@ void sh_xfer_start_server() */ sh_xfer_mark_dead (); + /* free the aliases list */ + zAVLFreeTree (all_aliases, free_alias); + all_aliases = NULL; + reset_count_dev_console(); reset_count_dev_time(); sl_trust_purge_user(); diff --git a/src/sh_xfer_syslog.c b/src/sh_xfer_syslog.c index ab516f5..8013e96 100644 --- a/src/sh_xfer_syslog.c +++ b/src/sh_xfer_syslog.c @@ -434,7 +434,7 @@ int sh_xfer_create_syslog_socket (int callerFlag) } #else - memset (&hints, '\0', sizeof (hints)); + memset (&hints, 0, sizeof (hints)); hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; hints.ai_socktype = SOCK_DGRAM; if (getaddrinfo (NULL, "syslog", &hints, &ai) != 0) @@ -1,7 +1,16 @@ #include "config_xor.h" #if defined(HAVE_POSIX_FADVISE) && defined(HAVE_MINCORE) + +#if defined(__sun) || defined(__sun__) || defined(sun) +#define _XOPEN_SOURCE 500 +#else #define _XOPEN_SOURCE 600 +#endif + +#if defined(__GNUC__) +#define _DEFAULT_SOURCE +#endif #define _BSD_SOURCE #endif @@ -247,9 +256,9 @@ int dlog (int flag, const char * file, int line, const char *fmt, ...) if (flag == 1) { sl_snprintf (val, 81, _("\n--------- %10s "), file); - sl_strlcpy (msg, val, 80); + sl_strlcpy (msg, val, sizeof(msg)); sl_snprintf (val, 81, _(" --- %6d ---------\n"), line); - sl_strlcat (msg, val, 80); + sl_strlcat (msg, val, sizeof(msg)); sh_log_console (msg); } @@ -578,11 +587,37 @@ int sl_get_cap_qdel() { return 0; } /* * Have memset in a different translation unit (i.e. this) to prevent - * it to get optimized away + * it to get optimized away ...not safe with link-time optimisation... */ -void *sl_memset(void *s, int c, size_t n) +void * sl_memset(void *s, int c, size_t n) { - return memset(s, c,n); + /* See: + * https://www.usenix.org/sites/default/files/conference/protected-files/usenixsecurity17_slides_zhaomo_yang.pdf + */ +#if defined(HAVE_EXPLICIT_MEMSET) + return explicit_memset(s, c, n); +#elif defined(HAVE_EXPLICIT_BZERO) + if (c == 0) { + explicit_bzero(s, n); + return s; + } else { + return memset(s, c, n); + } +#elif defined(__GNUC__) + memset(s, c, n); + __asm__ __volatile__ ("" ::"r"(s): "memory"); /* compiler barrier */ + return s; +#else + if (c == 0) { + size_t i; + volatile unsigned char * t_s = (volatile unsigned char *)s; + for (i=0; i<n; ++i) + t_s[i] = 0; + return s; + } else { + return memset(s, c, n); + } +#endif } @@ -1069,6 +1104,40 @@ int sl_strcmp(const char * a, const char * b) return (-7); /* default to not equal */ } +/* Does not report sign. */ +int sl_ts_strncmp(const char * a, const char * b, size_t n) +{ +#ifdef SL_FAIL_ON_ERROR + SL_REQUIRE (a != NULL, _("a != NULL")); + SL_REQUIRE (b != NULL, _("b != NULL")); + SL_REQUIRE (n > 0, _("n > 0")); +#endif + + if (a != NULL && b != NULL) + { + const unsigned char *a1 = (const unsigned char *)a; + const unsigned char *b1 = (const unsigned char *)b; + size_t i; + int retval=0; + /* The simple index based access is optimized best by the + * compiler (tested with gcc 7.3.0). */ + for (i = 0; i < n; ++i) + { + if (a1[i] == '\0' || b1[i] == '\0') + break; + retval |= (a1[i] ^ b1[i]); + } + /* if (retval == 0) --> false (0) */ + return (retval != 0); + } + else if (a == NULL && b != NULL) + return (-1); + else if (a != NULL && b == NULL) + return (1); + else + return (-7); /* default to not equal */ +} + int sl_strncmp(const char * a, const char * b, size_t n) { #ifdef SL_FAIL_ON_ERROR @@ -1767,6 +1836,7 @@ SL_TICKET sl_make_ticket (const char * ofile, int oline, { free (ofiles[fd]); ofiles[fd] = NULL; + /* cppcheck-suppress memleak */ SL_IRETURN(SL_EMEM, _("sl_make_ticket")); } @@ -1779,6 +1849,7 @@ SL_TICKET sl_make_ticket (const char * ofile, int oline, (void) free (ofiles[fd]->path); (void) free (ofiles[fd]); ofiles[fd] = NULL; + /* cppcheck-suppress memleak */ SL_IRETURN(ticket, _("sl_make_ticket")); } @@ -1792,6 +1863,7 @@ SL_TICKET sl_make_ticket (const char * ofile, int oline, sl_strlcpy(ofiles[fd]->ofile, ofile, SL_OFILE_SIZE); ofiles[fd]->oline = oline; + /* cppcheck-suppress memleak */ SL_IRETURN(ticket, _("sl_make_ticket")); } @@ -2376,6 +2448,7 @@ int sl_close (SL_TICKET ticket) TPT((0, FIL__, __LINE__, _("msg=<Error fclosing file.>, fd=<%d>, err=<%s>\n"), fd, strerror(errno))); + SL_IRETURN(SL_ECLOSE, _("sl_close")); } } else @@ -2385,6 +2458,7 @@ int sl_close (SL_TICKET ticket) TPT((0, FIL__, __LINE__, _("msg=<Error closing file.>, fd=<%d>, err=<%s>\n"), fd, strerror(errno))); + SL_IRETURN(SL_ECLOSE, _("sl_close")); } } @@ -2559,8 +2633,8 @@ int sl_read_timeout_prep (SL_TICKET ticket) } -int sl_read_timeout_fd (int fd, void * buf_in, size_t count, - int timeout, int is_nonblocking) +static int sl_read_timeout_fd_int (int fd, void * buf_in, size_t count, + int timeout, int is_nonblocking, int once) { int sflags = 0; fd_set readfds; @@ -2609,7 +2683,7 @@ int sl_read_timeout_fd (int fd, void * buf_in, size_t count, { bytes += byteread; count -= byteread; buf += byteread; - if (count == 0) + if (count == 0 || once == S_TRUE) break; } else if (byteread == 0) @@ -2693,6 +2767,18 @@ int sl_read_timeout_fd (int fd, void * buf_in, size_t count, return ((int) bytes); } +int sl_read_timeout_fd (int fd, void * buf_in, size_t count, + int timeout, int is_nonblocking) +{ + return sl_read_timeout_fd_int (fd, buf_in, count, timeout, is_nonblocking, S_FALSE); +} + +int sl_read_timeout_fd_once (int fd, void * buf_in, size_t count, + int timeout, int is_nonblocking) +{ + return sl_read_timeout_fd_int (fd, buf_in, count, timeout, is_nonblocking, S_TRUE); +} + int sl_read_timeout (SL_TICKET ticket, void * buf_in, size_t count, int timeout, int is_nonblocking) { diff --git a/src/sstrip.c b/src/sstrip.c deleted file mode 100644 index a296561..0000000 --- a/src/sstrip.c +++ /dev/null @@ -1,538 +0,0 @@ -/* sstrip, version 2.0: Copyright (C) 1999-2001 by Brian Raiter, under the - * GNU General Public License. No warranty. See LICENSE for details. - */ - -/* Modified for portability and 64bit/32bit elf executables, Rainer Wichmann */ - -#include "config.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> - -#if !defined(__ia64) && !defined(__ia64__) && !defined(__itanium__) && \ - !defined(__alpha) && !defined(__alpha__) && \ - (defined(HAVE_ELF_H) || defined(HAVE_LINUX_ELF_H)) && \ - (defined(__linux__) || defined(__FreeBSD__)) && \ - (defined(__i386__) || defined(__i386) || defined(i386)) - -/* || defined(__sun) || defined(__sun__) || defined(sun) */ - - -#if defined(HAVE_ELF_H) -#include <elf.h> -#else -#include <linux/elf.h> -#endif - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -#ifndef ELFCLASS32 -#define ELFCLASS32 1 /* 32-bit objects */ -#endif -#ifndef ELFCLASS64 -#define ELFCLASS64 2 /* 64-bit objects */ -#endif - - - -/* The name of the program. - */ -static char const *progname; - -/* The name of the current file. - */ -static char const *filename; - - -/* A simple error-handling function. FALSE is always returned for the - * convenience of the caller. - */ -static int err(char const *errmsg) -{ - fprintf(stderr, "%s: %s: %s\n", progname, filename, errmsg); - return FALSE; -} - -/* A macro for I/O errors: The given error message is used only when - * errno is not set. - */ -#define ferr(msg) (err(errno ? strerror(errno) : (msg))) - -/* readelfheader() reads the ELF header into our global variable, and - * checks to make sure that this is in fact a file that we should be - * munging. - */ -static int readelfheader_32(int fd, Elf32_Ehdr *ehdr) -{ - errno = 0; - if (read(fd, ehdr, sizeof *ehdr) != sizeof *ehdr) - return ferr("missing or incomplete ELF header."); - - /* Check the ELF signature. - */ - if (!(ehdr->e_ident[EI_MAG0] == ELFMAG0 && - ehdr->e_ident[EI_MAG1] == ELFMAG1 && - ehdr->e_ident[EI_MAG2] == ELFMAG2 && - ehdr->e_ident[EI_MAG3] == ELFMAG3)) - return err("missing ELF signature."); - - /* Compare the file's class and endianness with the program's. - */ -#ifdef ELF_DATA - if (ehdr->e_ident[EI_DATA] != ELF_DATA) - return err("ELF file has different endianness."); -#endif - - if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) - return FALSE; - - /* Check the target architecture. - */ -#ifdef ELF_ARCH - if (ehdr->e_machine != ELF_ARCH) - return err("ELF file created for different architecture."); -#endif - - /* Verify the sizes of the ELF header and the program segment - * header table entries. - */ - if (ehdr->e_ehsize != sizeof(Elf32_Ehdr)) - return err("unrecognized ELF header size."); - if (ehdr->e_phentsize != sizeof(Elf32_Phdr)) - return err("unrecognized program segment header size."); - - /* Finally, check the file type. - */ - if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) - return err("not an executable or shared-object library."); - - return TRUE; -} - -static int readelfheader_64(int fd, Elf64_Ehdr *ehdr) -{ - errno = 0; - - if (lseek(fd, 0, SEEK_SET)) - return ferr("could not rewind file"); - - if (read(fd, ehdr, sizeof *ehdr) != sizeof *ehdr) - return ferr("missing or incomplete ELF header."); - - /* Check the ELF signature. - */ - if (!(ehdr->e_ident[EI_MAG0] == ELFMAG0 && - ehdr->e_ident[EI_MAG1] == ELFMAG1 && - ehdr->e_ident[EI_MAG2] == ELFMAG2 && - ehdr->e_ident[EI_MAG3] == ELFMAG3)) - return err("missing ELF signature."); - - /* Compare the file's class and endianness with the program's. - */ -#ifdef ELF_DATA - if (ehdr->e_ident[EI_DATA] != ELF_DATA) - return err("ELF file has different endianness."); -#endif - - if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) - return err("ELF file has different word size."); - - /* Check the target architecture. - */ -#ifdef ELF_ARCH - if (ehdr->e_machine != ELF_ARCH) - return err("ELF file created for different architecture."); -#endif - - /* Verify the sizes of the ELF header and the program segment - * header table entries. - */ - if (ehdr->e_ehsize != sizeof(Elf64_Ehdr)) - return err("unrecognized ELF header size."); - if (ehdr->e_phentsize != sizeof(Elf64_Phdr)) - return err("unrecognized program segment header size."); - - /* Finally, check the file type. - */ - if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) - return err("not an executable or shared-object library."); - - return TRUE; -} - -/* readphdrtable() loads the program segment header table into memory. - */ -static int readphdrtable_32(int fd, Elf32_Ehdr const *ehdr, Elf32_Phdr **phdrs) -{ - size_t size; - - if (!ehdr->e_phoff || !ehdr->e_phnum) - return err("ELF file has no program header table."); - - size = ehdr->e_phnum * sizeof **phdrs; - if (!(*phdrs = calloc(1,size))) - return err("Out of memory!"); - - errno = 0; - if (read(fd, *phdrs, size) != (ssize_t)size) - return ferr("missing or incomplete program segment header table."); - - return TRUE; -} - -static int readphdrtable_64(int fd, Elf64_Ehdr const *ehdr, Elf64_Phdr **phdrs) -{ - size_t size; - - if (!ehdr->e_phoff || !ehdr->e_phnum) - return err("ELF file has no program header table."); - - size = ehdr->e_phnum * sizeof **phdrs; - if (!(*phdrs = calloc(1,size))) - return err("Out of memory!"); - - errno = 0; - if (read(fd, *phdrs, size) != (ssize_t)size) - return ferr("missing or incomplete program segment header table."); - - return TRUE; -} - -/* getmemorysize() determines the offset of the last byte of the file - * that is referenced by an entry in the program segment header table. - * (Anything in the file after that point is not used when the program - * is executing, and thus can be safely discarded.) - */ -static int getmemorysize_32(Elf32_Ehdr const *ehdr, Elf32_Phdr const *phdrs, - unsigned long *newsize) -{ - Elf32_Phdr const *phdr; - unsigned long size, n; - unsigned int i; - - /* Start by setting the size to include the ELF header and the - * complete program segment header table. - */ - size = ehdr->e_phoff + ehdr->e_phnum * sizeof *phdrs; - if (size < sizeof *ehdr) - size = sizeof *ehdr; - - /* Then keep extending the size to include whatever data the - * program segment header table references. - */ - for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) { - if (phdr->p_type != PT_NULL) { - n = phdr->p_offset + phdr->p_filesz; - if (n > size) - size = n; - } - } - - *newsize = size; - return TRUE; -} - -static int getmemorysize_64(Elf64_Ehdr const *ehdr, Elf64_Phdr const *phdrs, - unsigned long *newsize) -{ - Elf64_Phdr const *phdr; - unsigned long size, n; - unsigned int i; - - /* Start by setting the size to include the ELF header and the - * complete program segment header table. - */ - size = ehdr->e_phoff + ehdr->e_phnum * sizeof *phdrs; - if (size < sizeof *ehdr) - size = sizeof *ehdr; - - /* Then keep extending the size to include whatever data the - * program segment header table references. - */ - for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) { - if (phdr->p_type != PT_NULL) { - n = phdr->p_offset + phdr->p_filesz; - if (n > size) - size = n; - } - } - - *newsize = size; - return TRUE; -} - -/* truncatezeros() examines the bytes at the end of the file's - * size-to-be, and reduces the size to exclude any trailing zero - * bytes. - */ -static int truncatezeros(int fd, unsigned long *newsize) -{ - unsigned char contents[1024]; - unsigned long size, n; - - size = *newsize; - do { - n = sizeof contents; - if (n > size) - n = size; - if (lseek(fd, size - n, SEEK_SET) == (off_t)-1) - return ferr("cannot seek in file."); - if (read(fd, contents, n) != (ssize_t)n) - return ferr("cannot read file contents"); - while (n && !contents[--n]) - --size; - } while (size && !n); - - /* Sanity check. - */ - if (!size) - return err("ELF file is completely blank!"); - - *newsize = size; - return TRUE; -} - -/* modifyheaders() removes references to the section header table if - * it was stripped, and reduces program header table entries that - * included truncated bytes at the end of the file. - */ -static int modifyheaders_32(Elf32_Ehdr *ehdr, Elf32_Phdr *phdrs, - unsigned long newsize) -{ - Elf32_Phdr *phdr; - unsigned int i; - - /* If the section header table is gone, then remove all references - * to it in the ELF header. - */ - if (ehdr->e_shoff >= newsize) { - ehdr->e_shoff = 0; - ehdr->e_shnum = 0; - ehdr->e_shentsize = 0; - ehdr->e_shstrndx = 0; - } - - /* The program adjusts the file size of any segment that was - * truncated. The case of a segment being completely stripped out - * is handled separately. - */ - for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) { - if (phdr->p_offset >= newsize) { - phdr->p_offset = newsize; - phdr->p_filesz = 0; - } else if (phdr->p_offset + phdr->p_filesz > newsize) { - phdr->p_filesz = newsize - phdr->p_offset; - } - } - - return TRUE; -} - -static int modifyheaders_64(Elf64_Ehdr *ehdr, Elf64_Phdr *phdrs, - unsigned long newsize) -{ - Elf64_Phdr *phdr; - unsigned int i; - - /* If the section header table is gone, then remove all references - * to it in the ELF header. - */ - if (ehdr->e_shoff >= newsize) { - ehdr->e_shoff = 0; - ehdr->e_shnum = 0; - ehdr->e_shentsize = 0; - ehdr->e_shstrndx = 0; - } - - /* The program adjusts the file size of any segment that was - * truncated. The case of a segment being completely stripped out - * is handled separately. - */ - for (i = 0, phdr = phdrs ; i < ehdr->e_phnum ; ++i, ++phdr) { - if (phdr->p_offset >= newsize) { - phdr->p_offset = newsize; - phdr->p_filesz = 0; - } else if (phdr->p_offset + phdr->p_filesz > newsize) { - phdr->p_filesz = newsize - phdr->p_offset; - } - } - - return TRUE; -} - -/* commitchanges() writes the new headers back to the original file - * and sets the file to its new size. - */ -static int commitchanges_32(int fd, Elf32_Ehdr const *ehdr, Elf32_Phdr *phdrs, - unsigned long newsize) -{ - size_t n; - - /* Save the changes to the ELF header, if any. - */ - if (lseek(fd, 0, SEEK_SET)) - return ferr("could not rewind file"); - errno = 0; - if (write(fd, ehdr, sizeof *ehdr) != sizeof *ehdr) - return err("could not modify file"); - - /* Save the changes to the program segment header table, if any. - */ - if (lseek(fd, ehdr->e_phoff, SEEK_SET) == (off_t)-1) { - err("could not seek in file."); - goto warning; - } - n = ehdr->e_phnum * sizeof *phdrs; - if (write(fd, phdrs, n) != (ssize_t)n) { - err("could not write to file"); - goto warning; - } - - /* Eleventh-hour sanity check: don't truncate before the end of - * the program segment header table. - */ - if (newsize < ehdr->e_phoff + n) - newsize = ehdr->e_phoff + n; - - /* Chop off the end of the file. - */ - if (ftruncate(fd, newsize)) { - err("could not resize file"); - goto warning; - } - - return TRUE; - - warning: - return err("ELF file may have been corrupted!"); -} - -static int commitchanges_64(int fd, Elf64_Ehdr const *ehdr, Elf64_Phdr *phdrs, - unsigned long newsize) -{ - size_t n; - - /* Save the changes to the ELF header, if any. - */ - if (lseek(fd, 0, SEEK_SET)) - return ferr("could not rewind file"); - errno = 0; - if (write(fd, ehdr, sizeof *ehdr) != sizeof *ehdr) - return err("could not modify file"); - - /* Save the changes to the program segment header table, if any. - */ - if (lseek(fd, ehdr->e_phoff, SEEK_SET) == (off_t)-1) { - err("could not seek in file."); - goto warning; - } - n = ehdr->e_phnum * sizeof *phdrs; - if (write(fd, phdrs, n) != (ssize_t)n) { - err("could not write to file"); - goto warning; - } - - /* Eleventh-hour sanity check: don't truncate before the end of - * the program segment header table. - */ - if (newsize < ehdr->e_phoff + n) - newsize = ehdr->e_phoff + n; - - /* Chop off the end of the file. - */ - if (ftruncate(fd, newsize)) { - err("could not resize file"); - goto warning; - } - - return TRUE; - - warning: - return err("ELF file may have been corrupted!"); -} - -/* main() loops over the cmdline arguments, leaving all the real work - * to the other functions. - */ -int main(int argc, char *argv[]) -{ - int fd; - int is_32bit_elf; - Elf32_Ehdr ehdr32; - Elf32_Phdr *phdrs32 = NULL; - Elf64_Ehdr ehdr64; - Elf64_Phdr *phdrs64 = NULL; - unsigned long newsize; - char **arg; - int failures = 0; - - if (argc < 2 || argv[1][0] == '-') { - printf("Usage: sstrip FILE...\n" - "sstrip discards all nonessential bytes from an executable.\n\n" - "Version 2.0 Copyright (C) 2000,2001 Brian Raiter.\n" - "This program is free software, licensed under the GNU\n" - "General Public License. There is absolutely no warranty.\n"); - return EXIT_SUCCESS; - } - - progname = argv[0]; - - for (arg = argv + 1 ; *arg != NULL ; ++arg) { - filename = *arg; - - fd = open(*arg, O_RDWR); - if (fd < 0) { - ferr("can't open"); - ++failures; - continue; - } - - if (readelfheader_32(fd, &ehdr32)) { - is_32bit_elf = TRUE; - } - else if (readelfheader_64(fd, &ehdr64)) { - is_32bit_elf = FALSE; - } - else { - close(fd); - return EXIT_FAILURE; - } - - if (is_32bit_elf) { - if (!(readphdrtable_32(fd, &ehdr32, &phdrs32) && - getmemorysize_32(&ehdr32, phdrs32, &newsize) && - truncatezeros(fd, &newsize) && - modifyheaders_32(&ehdr32, phdrs32, newsize) && - commitchanges_32(fd, &ehdr32, phdrs32, newsize))) - ++failures; - } - else { - if (!(readphdrtable_64(fd, &ehdr64, &phdrs64) && - getmemorysize_64(&ehdr64, phdrs64, &newsize) && - truncatezeros(fd, &newsize) && - modifyheaders_64(&ehdr64, phdrs64, newsize) && - commitchanges_64(fd, &ehdr64, phdrs64, newsize))) - ++failures; - } - - close(fd); - } - - return failures ? EXIT_FAILURE : EXIT_SUCCESS; -} - -#else - -int main() -{ - return (EXIT_SUCCESS); -} - -#endif diff --git a/src/t-test0.c b/src/t-test0.c index ed03554..034ca6e 100644 --- a/src/t-test0.c +++ b/src/t-test0.c @@ -165,7 +165,7 @@ mem_init(unsigned char *ptr, unsigned long size) if(size == 0) return; #if TEST > 3 - memset(ptr, '\0', size); + memset(ptr, 0, size); #endif for(i=0; i<size; i+=2047) { j = (unsigned long)ptr ^ i; @@ -389,7 +389,7 @@ malloc_test(unsigned long size, int bins, int max) #endif actions = RANDOM(&ld, ACTIONS_MAX); #if USE_MALLOC && MALLOC_DEBUG - if(actions < 2) { mallinfo(); } + if(actions < 2) { mallinfo2(); } #endif for(j=0; j<actions; j++) { b = RANDOM(&ld, p.bins); diff --git a/src/t-test1.c b/src/t-test1.c index 942f81d..9b3ebec 100644 --- a/src/t-test1.c +++ b/src/t-test1.c @@ -498,7 +498,7 @@ malloc_test(struct thread_st *st) #endif actions = RANDOM(&ld, ACTIONS_MAX); #if USE_MALLOC && MALLOC_DEBUG - if(actions < 2) { mallinfo(); } + if(actions < 2) { mallinfo2(); } #endif for(j=0; j<actions; j++) { b = RANDOM(&ld, p.bins); diff --git a/src/yulectl.c b/src/yulectl.c index 50a837b..8948695 100644 --- a/src/yulectl.c +++ b/src/yulectl.c @@ -47,8 +47,10 @@ #define SH_REQ_PASSWORD 1 #endif +#define SH_PW_SIZE 15 + static int sock = -1; -static char password[15] = ""; +static char password[SH_PW_SIZE] = ""; static int verbose = 0; #ifdef SH_STEALTH @@ -122,13 +124,10 @@ termination_handler (int signum) static char * safe_copy(char * to, const char * from, size_t size) { - if (to && from) + if (to && from && (size > 0)) { - strncpy (to, from, size); - if (size > 0) - to[size-1] = '\0'; - else - *to = '\0'; + strncpy (to, from, size-1); + to[size-1] = '\0'; } return to; } @@ -143,7 +142,13 @@ static int send_to_server (char * serversock, char * message) /* Initialize the server socket address. */ name.sun_family = AF_UNIX; - strncpy (name.sun_path, serversock, sizeof(name.sun_path) - 1); + memcpy(name.sun_path, serversock, sizeof(name.sun_path)); + name.sun_path[sizeof(name.sun_path)-1] = '\0'; + if (strlen(serversock) > strlen(name.sun_path)) + { + perror (_("ERROR: socket path too long")); + return -1; + } size = (offsetof (struct sockaddr_un, sun_path) + strlen (name.sun_path) + 1); @@ -400,7 +405,7 @@ static int get_passwd(char * message2, size_t size) /* 1) Password from environment */ pw = getenv(_("YULECTL_PASSWORD")); - if (pw && strlen(pw) < 15) + if (pw && strlen(pw) < SH_PW_SIZE) { strcpy(password, pw); strcpy(message2, password); @@ -412,7 +417,7 @@ static int get_passwd(char * message2, size_t size) if (get_home(home, sizeof(home)) < 0) return -1; - if ( (strlen(home) + strlen(_("/.yulectl_cred")) + 1) > 4096) + if ( (strlen(home) + strlen(_("/.yulectl_cred")) + 1) > sizeof(home)) { fprintf (stderr, "%s", _("ERROR: path for $HOME is too long.\n")); return -1; @@ -450,7 +455,7 @@ static int get_passwd(char * message2, size_t size) (void) rtrim(message2); - if (strlen(message2) > 14) + if (strlen(message2) > (SH_PW_SIZE -1)) { fprintf (stderr, "%s", _("ERROR: Password too long (max. 14 characters).\n")); |