/* 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" #ifdef HOST_IS_HPUX #define _XOPEN_SOURCE_EXTENDED #endif #include #include #include #include #include #include #include #include #include #include #ifndef S_SPLINT_S #include #else #define AF_INET 2 #endif #include #ifndef HAVE_LSTAT #define lstat stat #endif #include "samhain.h" #include "sh_error.h" #include "sh_calls.h" #undef FIL__ #define FIL__ _("sh_calls.c") char aud_err_message[64]; typedef struct cht_struct { char * str; unsigned long val; } cht_type; static cht_type aud_tab[] = { { N_("execve"), AUD_EXEC }, { N_("utime"), AUD_UTIME }, { N_("unlink"), AUD_UNLINK }, { N_("dup"), AUD_DUP }, { N_("chdir"), AUD_CHDIR }, { N_("open"), AUD_OPEN }, { N_("kill"), AUD_KILL }, { N_("exit"), AUD_EXIT }, { N_("fork"), AUD_FORK }, { N_("setuid"), AUD_SETUID }, { N_("setgid"), AUD_SETGID }, { N_("pipe"), AUD_PIPE }, { NULL, 0 } }; /* Set aud functions */ int sh_aud_set_functions(const char * str_s) { int i = 0; SL_ENTER(_("sh_aud_set_functions")); if (str_s == NULL) return -1; while (aud_tab[i].str != NULL) { if (NULL != sl_strstr (str_s, _(aud_tab[i].str))) { sh.flag.audit = 1; sh.flag.aud_mask |= aud_tab[i].val; } ++i; } SL_RETURN(0,_("sh_aud_set_functions")); } /* Need to catch EINTR for these functions. */ long int retry_sigaction(char * file, int line, int signum, const struct sigaction *act, struct sigaction *oldact) { int error; long int val_retry = -1; char errbuf[SH_ERRBUF_SIZE]; errno = 0; SL_ENTER(_("retry_sigaction")); do { val_retry = sigaction(signum, act, oldact); } while (val_retry < 0 && errno == EINTR); error = errno; if (val_retry < 0) { sh_error_handle ((-1), file, line, error, MSG_ERR_SIGACT, sh_error_message(error, errbuf, sizeof(errbuf)), (long) signum ); } errno = error; SL_RETURN(val_retry, _("retry_sigaction")); } static struct in_addr bind_addr; static int use_bind_addr = 0; int sh_calls_set_bind_addr (const char * str) { static int reject = 0; if (reject == 1) return (0); if (sh.flag.opts == S_TRUE) reject = 1; if (0 == /*@-unrecog@*/inet_aton(str, &bind_addr)/*@+unrecog@*/) { return -1; } use_bind_addr = 1; return 0; } long int retry_connect(char * file, int line, int sockfd, struct sockaddr *serv_addr, int addrlen) { int error; long int val_retry = 0; static struct sockaddr_in new_addr; char errbuf[SH_ERRBUF_SIZE]; SL_ENTER(_("retry_connect")); errno = 0; if (0 != use_bind_addr) { memcpy(&new_addr.sin_addr, &bind_addr, sizeof(struct in_addr)); new_addr.sin_family = AF_INET; val_retry = /*@-unrecog@*/bind(sockfd, (struct sockaddr*)&new_addr, sizeof(struct sockaddr_in))/*@+unrecog@*/; } if (val_retry == 0) { do { val_retry = /*@-unrecog@*/connect(sockfd, serv_addr, addrlen)/*@+unrecog@*/; } while (val_retry < 0 && errno == EINTR); } error = errno; if (val_retry != 0) { /* ugly cast back to struct sockaddr_in :-( */ sh_error_handle ((-1), file, line, error, MSG_ERR_CONNECT, sh_error_message(error, errbuf, sizeof(errbuf)), (long) sockfd, /*@-unrecog -type@*/ (long) ntohs(((struct sockaddr_in *)serv_addr)->sin_port), /*@+unrecog +type@*/ #ifdef HAVE_INET_ATON /*@-unrecog -type@*/ inet_ntoa( ((struct sockaddr_in *)serv_addr)->sin_addr ) /*@+unrecog +type@*/ #else _("unknown") #endif ); } errno = error; SL_RETURN(val_retry, _("retry_connect")); } long int retry_accept(char * file, int line, int fd, struct sockaddr *serv_addr, int * addrlen) { int error; long int val_retry = -1; char errbuf[SH_ERRBUF_SIZE]; ACCEPT_TYPE_ARG3 my_addrlen = (ACCEPT_TYPE_ARG3) *addrlen; errno = 0; SL_ENTER(_("retry_accept")); do { val_retry = /*@-unrecog@*/accept(fd, serv_addr, &my_addrlen)/*@+unrecog@*/; } while (val_retry < 0 && errno == EINTR); *addrlen = (int) my_addrlen; error = errno; if (val_retry < 0) { sh_error_handle ((-1), file, line, error, MSG_ERR_ACCEPT, sh_error_message(error, errbuf, sizeof(errbuf)), (long) fd ); } errno = error; SL_RETURN(val_retry, _("retry_accept")); } long int retry_lstat(char * file, int line, const char *file_name, struct stat *buf) { int error; long int val_retry = -1; char errbuf[SH_ERRBUF_SIZE]; SL_ENTER(_("retry_lstat")); do { val_retry = /*@-unrecog@*/lstat (file_name, buf)/*@+unrecog@*/; } while (val_retry < 0 && errno == EINTR); error = errno; if (val_retry < 0) { (void) sl_strlcpy(aud_err_message, sh_error_message(error, errbuf, sizeof(errbuf)), 64); sh_error_handle ((-1), file, line, error, MSG_ERR_LSTAT, sh_error_message(error, errbuf, sizeof(errbuf)), file_name ); } errno = error; SL_RETURN(val_retry, _("retry_lstat")); } long int retry_stat(char * file, int line, const char *file_name, struct stat *buf) { int error; long int val_retry = -1; char errbuf[SH_ERRBUF_SIZE]; SL_ENTER(_("retry_stat")); do { val_retry = stat (file_name, buf); } while (val_retry < 0 && errno == EINTR); error = errno; if (val_retry < 0) { (void) sl_strlcpy(aud_err_message, sh_error_message(error, errbuf, sizeof(errbuf)), 64); sh_error_handle ((-1), file, line, error, MSG_ERR_STAT, sh_error_message(error, errbuf, sizeof(errbuf)), file_name ); } errno = error; SL_RETURN(val_retry, _("retry_stat")); } long int retry_fstat(char * file, int line, int filed, struct stat *buf) { int error; long int val_retry = -1; char errbuf[SH_ERRBUF_SIZE]; SL_ENTER(_("retry_fstat")); do { val_retry = fstat (filed, buf); } while (val_retry < 0 && errno == EINTR); error = errno; if (val_retry < 0) { sh_error_handle ((-1), file, line, error, MSG_ERR_FSTAT, sh_error_message(error, errbuf, sizeof(errbuf)), (long) filed ); } errno = error; SL_RETURN(val_retry, _("retry_fstat")); } long int retry_fcntl(char * file, int line, int fd, int cmd, long arg) { int error; long int val_retry = -1; char errbuf[SH_ERRBUF_SIZE]; errno = 0; SL_ENTER(_("retry_fcntl")); if (cmd == F_GETFD || cmd == F_GETFL) { do { val_retry = fcntl(fd, cmd); } while (val_retry < 0 && errno == EINTR); } else { do { val_retry = fcntl(fd, cmd, arg); } while (val_retry < 0 && errno == EINTR); } error = errno; if (val_retry < 0) { sh_error_handle ((-1), file, line, error, MSG_ERR_FCNTL, sh_error_message(error, errbuf, sizeof(errbuf)), (long) fd, (long) cmd, arg ); } errno = error; SL_RETURN(val_retry, _("retry_fcntl")); } long int retry_msleep (int sec, int millisec) { int result = 0; #if defined(HAVE_NANOSLEEP) struct timespec req, rem; #endif SL_ENTER(_("retry_fcntl")); errno = 0; if (millisec > 999) millisec = 999; if (millisec < 0) millisec = 0; if (sec < 0) sec = 0; #if defined(HAVE_NANOSLEEP) /*@-usedef@*/ req.tv_sec = sec; rem.tv_sec = 0; req.tv_nsec = millisec * 1000000; rem.tv_nsec = 0; /*@+usedef@*/ do { result = /*@-unrecog@*/nanosleep(&req, &rem)/*@+unrecog@*/; req.tv_sec = rem.tv_sec; rem.tv_sec = 0; req.tv_nsec = rem.tv_nsec; rem.tv_nsec = 0; } while ((result == -1) && (errno == EINTR)); #else if (sec > 0) { sleep (sec); } else { #ifdef HAVE_USLEEP if (millisec > 0) { usleep(1000 * millisec); } #else if (millisec > 0) { sleep (1); } #endif } #endif SL_RETURN(result, _("retry_msleep")); } /*************************************************** * * Audit these functions. * ***************************************************/ long int retry_aud_execve (char * file, int line, const char *dateiname, char * argv[], char * envp[]) { uid_t a = geteuid(); gid_t b = getegid(); int i; int error; char errbuf[SH_ERRBUF_SIZE]; SL_ENTER(_("retry_aud_execve")); if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_EXEC) != 0) sh_error_handle ((-1), file, line, 0, MSG_AUD_EXEC, dateiname, (long) a, (long) b ); do { i = execve(dateiname, argv, envp); } while (i < 0 && errno == EINTR); error = errno; if (i < 0) { sh_error_handle ((-1), file, line, error, MSG_ERR_EXEC, sh_error_message(error, errbuf, sizeof(errbuf)), dateiname, (long) a, (long) b ); } errno = error; SL_RETURN(i, _("retry_aud_execve")); } long int retry_aud_utime (char * file, int line, char * path, struct utimbuf *buf) { long int val_return; int error; char errbuf[SH_ERRBUF_SIZE]; errno = 0; SL_ENTER(_("retry_aud_utime")); do { val_return = utime (path, buf); } while (val_return < 0 && errno == EINTR); error = errno; if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_UTIME) != 0) sh_error_handle ((-1), file, line, 0, MSG_AUD_UTIME, path, (unsigned long) buf->actime, (unsigned long) buf->modtime); if (val_return < 0) { sh_error_handle ((-1), file, line, error, MSG_ERR_UTIME, sh_error_message(error, errbuf, sizeof(errbuf)), path, (unsigned long) buf->actime, (unsigned long) buf->modtime); } errno = error; SL_RETURN(val_return, _("retry_aud_utime")); } long int retry_aud_unlink (char * file, int line, char * path) { long int val_return; int error; char errbuf[SH_ERRBUF_SIZE]; errno = 0; SL_ENTER(_("retry_aud_unlink")); do { val_return = unlink (path); } while (val_return < 0 && errno == EINTR); error = errno; if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_UNLINK) != 0) sh_error_handle ((-1), file, line, 0, MSG_AUD_UNLINK, path); if (val_return < 0) { sh_error_handle ((-1), file, line, error, MSG_ERR_UNLINK, sh_error_message(error, errbuf, sizeof(errbuf)), path); } errno = error; SL_RETURN(val_return, _("retry_aud_unlink")); } long int retry_aud_dup2 (char * file, int line, int fd, int fd2) { long int val_return; int error; char errbuf[SH_ERRBUF_SIZE]; errno = 0; SL_ENTER(_("retry_aud_dup2")); do { val_return = dup2 (fd, fd2); } while (val_return < 0 && errno == EINTR); error = errno; if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_DUP) != 0) sh_error_handle ((-1), file, line, 0, MSG_AUD_DUP, (long) fd, val_return); if (val_return < 0) { sh_error_handle ((-1), file, line, error, MSG_ERR_DUP, sh_error_message(error, errbuf, sizeof(errbuf)), (long) fd, val_return); } errno = error; SL_RETURN(val_return, _("retry_aud_dup2")); } long int retry_aud_dup (char * file, int line, int fd) { long int val_return; int error; char errbuf[SH_ERRBUF_SIZE]; errno = 0; SL_ENTER(_("retry_aud_dup")); do { val_return = dup (fd); } while (val_return < 0 && errno == EINTR); error = errno; if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_DUP) != 0) sh_error_handle ((-1), file, line, 0, MSG_AUD_DUP, (long) fd, val_return); if (val_return < 0) { sh_error_handle ((-1), file, line, error, MSG_ERR_DUP, sh_error_message(error, errbuf, sizeof(errbuf)), (long) fd, val_return); } errno = error; SL_RETURN(val_return, _("retry_aud_dup")); } long int retry_aud_chdir (char * file, int line, const char *path) { long int val_return; int error = 0; char errbuf[SH_ERRBUF_SIZE]; errno = 0; SL_ENTER(_("retry_aud_chdir")); do { val_return = chdir (path); } while (val_return < 0 && errno == EINTR); error = errno; if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_CHDIR) != 0) sh_error_handle ((-1), file, line, 0, MSG_AUD_CHDIR, path); if (val_return < 0) { sh_error_handle ((-1), file, line, error, MSG_ERR_CHDIR, sh_error_message(error, errbuf, sizeof(errbuf)), path); } errno = error; SL_RETURN(val_return, _("retry_aud_chdir")); } long int aud_open_noatime (char * file, int line, int privs, const char *pathname, int flags, mode_t mode, int * o_noatime) { long int val_return; int error; char errbuf[SH_ERRBUF_SIZE]; SL_ENTER(_("aud_open")); val_return = open (pathname, *o_noatime|flags, mode); if ((val_return < 0) && (*o_noatime != 0)) { val_return = open (pathname, flags, mode); if (val_return >= 0) *o_noatime = 0; } error = errno; /*@-noeffect@*/ (void) privs; /* fix compiler warning */ /*@+noeffect@*/ if (val_return < 0) { (void) sl_strlcpy(aud_err_message, sh_error_message(error, errbuf, sizeof(errbuf)), 64); } if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_OPEN) != 0) { sh_error_handle ((-1), file, line, 0, MSG_AUD_OPEN, pathname, (long) flags, (long) mode, val_return); } if (val_return < 0) { sh_error_handle ((-1), file, line, error, MSG_ERR_OPEN, sh_error_message(error, errbuf, sizeof(errbuf)), pathname, (long) flags, (long) mode, val_return); } errno = error; SL_RETURN(val_return, _("aud_open")); } long int aud_open (char * file, int line, int privs, const char *pathname, int flags, mode_t mode) { long int val_return; int error; char errbuf[SH_ERRBUF_SIZE]; SL_ENTER(_("aud_open")); val_return = open (pathname, flags, mode); error = errno; /*@-noeffect@*/ (void) privs; /* fix compiler warning */ /*@+noeffect@*/ if (val_return < 0) { (void) sl_strlcpy(aud_err_message, sh_error_message(error, errbuf, sizeof(errbuf)), 64); } if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_OPEN) != 0) { sh_error_handle ((-1), file, line, 0, MSG_AUD_OPEN, pathname, (long) flags, (long) mode, val_return); } if (val_return < 0) { sh_error_handle ((-1), file, line, error, MSG_ERR_OPEN, sh_error_message(error, errbuf, sizeof(errbuf)), pathname, (long) flags, (long) mode, val_return); } errno = error; SL_RETURN(val_return, _("aud_open")); } long int aud_kill (char * file, int line, pid_t pid, int sig) { int myerror; long int val_return = kill (pid, sig); char errbuf[SH_ERRBUF_SIZE]; myerror = errno; SL_ENTER(_("aud_kill")); if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_KILL) != 0) sh_error_handle ((-1), file, line, 0, MSG_AUD_KILL, (long) pid, (long) sig); if (val_return < 0) { sh_error_handle ((-1), file, line, myerror, MSG_ERR_KILL, sh_error_message(myerror, errbuf, sizeof(errbuf)), (long) pid, (long) sig); } errno = myerror; SL_RETURN(val_return, _("aud_kill")); } /*@noreturn@*/ void aud_exit (char * file, int line, int fd) { if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_EXIT) != 0) sh_error_handle ((-1), file, line, 0, MSG_AUD_EXIT, (long) fd); SL_ENTER(_("aud_exit")); sh.flag.exit = fd; exit(fd); } /*@noreturn@*/ void aud__exit (char * file, int line, int fd) { if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_EXIT) != 0) sh_error_handle ((-1), file, line, 0, MSG_AUD_EXIT, (long) fd); SL_ENTER(_("aud__exit")); sh.flag.exit = fd; _exit(fd); } pid_t aud_fork (char * file, int line) { int error; pid_t i = fork(); char errbuf[SH_ERRBUF_SIZE]; error = errno; SL_ENTER(_("aud_fork")); if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_FORK) != 0 && (i > 0)) sh_error_handle ((-1), file, line, 0, MSG_AUD_FORK, (long) i); if (i == (pid_t) -1) { sh_error_handle ((-1), file, line, error, MSG_ERR_FORK, sh_error_message(error, errbuf, sizeof(errbuf)), (long) i); } errno = error; SL_RETURN(i, _("aud_fork")); } int aud_setuid (char * file, int line, uid_t uid) { int error = 0; int i = 0; char errbuf[SH_ERRBUF_SIZE]; SL_ENTER(_("aud_setuid")); if (uid != (uid_t) 0) { i = setuid(uid); error = errno; } if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_SETUID) != 0) sh_error_handle ((-1), file, line, 0, MSG_AUD_SETUID, (long) uid); if (uid == (uid_t) 0) { i = setuid(uid); error = errno; } if (i < 0) { sh_error_handle ((-1), file, line, error, MSG_ERR_SETUID, sh_error_message(error, errbuf, sizeof(errbuf)), (long) uid); } errno = error; SL_RETURN(i, _("aud_setuid")); } int aud_setgid (char * file, int line, gid_t gid) { int error = 0; int i = 0; char errbuf[SH_ERRBUF_SIZE]; SL_ENTER(_("aud_setgid")); if (gid != (gid_t) 0) { i = setgid(gid); error = errno; } if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_SETGID) != 0) sh_error_handle ((-1), file, line, 0, MSG_AUD_SETGID, (long) gid); if (gid == (gid_t) 0) { i = setgid(gid); error = errno; } if (i < 0) { sh_error_handle ((-1), file, line, error, MSG_ERR_SETGID, sh_error_message(error, errbuf, sizeof(errbuf)), (long) gid); } errno = error; SL_RETURN(i, _("aud_setgid")); } int aud_pipe (char * file, int line, int * modus) { int error; int i = pipe (modus); char errbuf[SH_ERRBUF_SIZE]; SL_ENTER(_("aud_pipe")); error = errno; if (sh.flag.audit != 0 && (sh.flag.aud_mask & AUD_PIPE) != 0) { if (i < 0) sh_error_handle ((-1), file, line, 0, MSG_AUD_PIPE, (long) 0, (long) 0); else sh_error_handle ((-1), file, line, 0, MSG_AUD_PIPE, (long) modus[0], (long) modus[1]); } if (i < 0) { if (i < 0) sh_error_handle ((-1), file, line, error, MSG_ERR_PIPE, sh_error_message(error), (long) 0, (long) 0); else sh_error_handle ((-1), file, line, error, MSG_ERR_PIPE, sh_error_message(error, errbuf, sizeof(errbuf)), (long) modus[0], (long) modus[1]); } SL_RETURN(i, _("aud_pipe")); }