/* SAMHAIN file system integrity testing */ /* Copyright (C) 2008 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 #include #include #include #include #ifdef HAVE_DIRENT_H #include #define NAMLEN(dirent) sl_strlen((dirent)->d_name) #else #define dirent direct #define NAMLEN(dirent) (dirent)->d_namlen #ifdef HAVE_SYS_NDIR_H #include #endif #ifdef HAVE_SYS_DIR_H #include #endif #ifdef HAVE_NDIR_H #include #endif #endif #define NEED_ADD_DIRENT #if defined(SH_USE_PORTCHECK) && (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)) #if defined(__linux__) #include "samhain.h" #include "sh_error_min.h" #include "sh_utils.h" #include "sh_pthread.h" #define FIL__ _("sh_port2proc.c") static size_t sh_minpid = 0x0001; static size_t sh_maxpid = 0x8000; #ifndef HAVE_LSTAT #define lstat(x,y) stat(x,y) #endif /* HAVE_LSTAT */ #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 struct sock_store { unsigned long sock; size_t pid; char * path; char * user; struct sock_store * next; }; /* /proc: * linux: /proc/pid/exe * freebsd: /proc/pid/file * solaris10: /proc/pid/path/a.out */ static void get_user_and_path (struct sock_store * add) { extern char * sh_unix_getUIDname (int level, uid_t uid, char * out, size_t len); char path[128]; char * buf; struct stat sbuf; int len; char * tmp; sl_snprintf (path, sizeof(path), "/proc/%ld/exe", (unsigned long) add->pid); if (0 == retry_lstat(FIL__, __LINE__, path, &sbuf) && S_ISLNK(sbuf.st_mode)) { goto linkread; } sl_snprintf (path, sizeof(path), "/proc/%ld/file", (unsigned long) add->pid); if (0 == retry_lstat(FIL__, __LINE__, path, &sbuf) && S_ISLNK(sbuf.st_mode)) { goto linkread; } sl_snprintf (path, sizeof(path), "/proc/%ld/path/a.out", (unsigned long) add->pid); if (0 == retry_lstat(FIL__, __LINE__, path, &sbuf) && S_ISLNK(sbuf.st_mode)) { goto linkread; } return; linkread: buf = SH_ALLOC(PATH_MAX); len = readlink(path, buf, PATH_MAX); /* flawfinder: ignore */ len = (len >= PATH_MAX) ? (PATH_MAX-1) : len; if (len > 0) { buf[len] = '\0'; add->path = buf; } else { SH_FREE(buf); } add->user = SH_ALLOC(USER_MAX); tmp = sh_unix_getUIDname (SH_ERR_ALL, sbuf.st_uid, add->user, USER_MAX); if (!tmp) sl_snprintf (add->user, USER_MAX, "%ld", (unsigned long) sbuf.st_uid); return; } #if defined(__linux__) #define PROC_PID_MAX _("/proc/sys/kernel/pid_max") static int proc_max_pid (size_t * procpid) { char * ret; unsigned long pid; FILE * fd; char str[128]; char * ptr; SL_ENTER(_("proc_max_pid")); if (0 == access(PROC_PID_MAX, R_OK)) /* flawfinder: ignore */ { if (NULL != (fd = fopen(PROC_PID_MAX, "r"))) { str[0] = '\0'; ret = fgets(str, 128, fd); if (ret && *str != '\0') { pid = strtoul(str, &ptr, 0); if (*ptr == '\0' || *ptr == '\n') { fclose(fd); *procpid = (size_t) pid; SL_RETURN(0, _("proc_max_pid")); } } fclose(fd); } } SL_RETURN((-1), _("proc_max_pid")); } #else static int proc_max_pid(size_t * procpid) { *procpid = sh_maxpid; return 0; } #endif static struct sock_store * socklist = NULL; static void del_sock_all() { struct sock_store * del = socklist; while (del) { socklist = del->next; if (del->path) SH_FREE(del->path); if (del->user) SH_FREE(del->user); SH_FREE(del); del = socklist; } socklist = NULL; return; } static void add_sock(unsigned long sock, size_t pid) { struct sock_store * add = SH_ALLOC(sizeof(struct sock_store)); add->sock = sock; add->pid = pid; add->path = NULL; add->user = NULL; SH_MUTEX_LOCK(mutex_thread_nolog); get_user_and_path(add); SH_MUTEX_UNLOCK(mutex_thread_nolog); add->next = socklist; socklist = add; return; } static void check_and_add_sock(char * fbuf, size_t pid) { if (0 == strncmp(_("socket:["), fbuf, 8)) { char * end; unsigned long sock; size_t len = strlen(fbuf); if (fbuf[len-1] == ']') fbuf[len-1] = '\0'; sock = strtoul(&fbuf[8], &end, 0); if (*end == '\0' && fbuf[8] != '\0') { add_sock(sock, pid); } } } static void fetch_socks(size_t pid) { char path[128]; DIR * dir; sl_snprintf(path, sizeof(path), _("/proc/%lu/fd"), (unsigned long) pid); dir = opendir(path); if (dir) { struct dirent *entry; while (NULL != (entry = readdir(dir))) { char fpath[384]; char fbuf[64]; int ret; /* /proc/PID/fd/N-> socket:[15713] */ sl_snprintf(fpath, sizeof(fpath), _("%s/%s"), path, entry->d_name); ret = readlink(fpath, fbuf, sizeof(fbuf)-1); /* flawfinder: ignore */ if (ret > 0) { fbuf[ret] = '\0'; check_and_add_sock(fbuf, pid); } } closedir(dir); } } int sh_port2proc_prepare() { size_t i; if (0 != proc_max_pid(&sh_maxpid)) { SH_MUTEX_LOCK(mutex_thread_nolog); sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN, _("Failed to detect max_pid"), _("sh_port2proc")); SH_MUTEX_UNLOCK(mutex_thread_nolog); SL_RETURN ((-1), _("sh_port2proc")); } /* Delete old socket list and re-create it */ del_sock_all(); for (i = sh_minpid; i < sh_maxpid; ++i) { fetch_socks(i); } return 0; } #include #include #include char * sh_port2proc_query(int proto, struct in_addr * saddr, int sport, char * user, size_t userlen) { FILE * fd; if (proto == IPPROTO_TCP) fd = fopen("/proc/net/tcp", "r"); else fd = fopen("/proc/net/udp", "r"); if (fd) { int n, iface, port, inode; char line[512]; while (NULL != fgets(line, sizeof(line), fd)) { if (4 == sscanf(line, "%d: %X:%X %*X:%*X %*X %*X:%*X %*X:%*X %*X %*d %*d %d %*s", &n, &iface, &port, &inode)) { struct in_addr haddr; haddr.s_addr = (unsigned long)iface; if (haddr.s_addr == saddr->s_addr && port == sport) { struct sock_store * new = socklist; while (new) { if ((unsigned int)inode == new->sock) { fclose(fd); if (new->path) { if (new->user) sl_strlcpy(user, new->user, userlen); else sl_strlcpy(user, "-", userlen); return sh_util_strdup(new->path); } goto err_out; } new = new->next; } } } } fclose(fd); } err_out: sl_strlcpy(user, "0", userlen); return sh_util_strdup("-"); } #else /* !defined(__linux__) */ char * sh_port2proc_query(int proto, struct in_addr * saddr, int sport, char * user, size_t userlen) { (void) proto; (void) saddr; (void) sport; sl_strlcpy(user, "-", userlen); return sh_util_strdup("-"); } int sh_port2proc_prepare() { return 0; } #endif #endif /* defined(SH_USE_PORTCHECK) */