Index: trunk/src/sh_port2proc.c
===================================================================
--- trunk/src/sh_port2proc.c	(revision 192)
+++ trunk/src/sh_port2proc.c	(revision 193)
@@ -46,5 +46,10 @@
 #if defined(SH_USE_PORTCHECK) && (defined (SH_WITH_CLIENT) || defined (SH_STANDALONE))
 
-#if defined(__linux__)
+/****************************************************************************
+ *
+ *  >>> COMMON CODE <<<
+ *
+ ****************************************************************************/
+#if defined(__linux__) || defined(__FreeBSD__)
  
 #include "samhain.h"
@@ -55,4 +60,14 @@
 #define FIL__  _("sh_port2proc.c")
 
+#endif
+
+/****************************************************************************
+ *
+ *  >>> LINUX CODE <<<
+ *
+ ****************************************************************************/
+
+#if defined(__linux__)
+
 static  size_t  sh_minpid = 0x0001;
 static  size_t  sh_maxpid = 0x8000;
@@ -63,9 +78,9 @@
 
 #if defined(S_IFLNK) && !defined(S_ISLNK)
-#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
 #else
-#if !defined(S_ISLNK)
-#define S_ISLNK(mode) (0)
-#endif
+# if !defined(S_ISLNK)
+#  define S_ISLNK(mode) (0)
+# endif
 #endif
 
@@ -294,4 +309,6 @@
 #include <arpa/inet.h>
 
+/* returns the command and fills the 'user' array 
+ */
 char * sh_port2proc_query(int proto, struct in_addr * saddr, int sport,
 			  char * user, size_t userlen)
@@ -350,5 +367,449 @@
 }
 
-#else /* !defined(__linux__) */
+
+/****************************************************************************
+ *
+ *  >>> FREEBSD CODE <<<
+ *
+ ****************************************************************************/
+
+#elif defined(__FreeBSD__)
+
+/* Uses code from sockstat.c. Error and memory handling modified.
+ * Only required functions from sockstat.c are included.
+ */
+
+/*-
+ * Copyright (c) 2002 Dag-Erling Co<EF>dan Sm<F8>rgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/sockstat/sockstat.c,v 1.13.2.1.4.1 2008/10/02 02:57:24 kensmith Exp $");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/file.h>
+#include <sys/user.h>
+
+#include <sys/un.h>
+#include <sys/unpcb.h>
+
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_seq.h>
+#include <netinet/tcp_var.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+
+static int       opt_4 = 1;         /* Show IPv4 sockets */
+static int       opt_6 = 0;         /* Show IPv6 sockets */
+static int       opt_c = 0;         /* Show connected sockets */
+static int       opt_l = 1;         /* Show listening sockets */
+static int       opt_u = 0;         /* Show Unix domain sockets */
+static int       opt_v = 0;         /* Verbose mode */
+
+struct sock {
+        void *socket;
+        void *pcb;
+        int vflag;
+        int family;
+        int proto;
+
+        struct sockaddr_storage laddr;
+        struct sockaddr_storage faddr;
+        struct sock *next;
+};
+
+#define HASHSIZE 1009
+static struct sock *sockhash[HASHSIZE];
+
+static struct xfile *xfiles;
+static int nxfiles;
+
+
+static void * xrealloc(void * buf, size_t len0, size_t len)
+{
+  if (len > 0)
+    {
+      void xbuf = SH_ALLOC(len);
+      memcpy(xbuf, buf, len0);
+      SH_FREE(buf);
+      return xbuf;
+    }
+  SH_FREE(buf);
+  return NULL;
+}
+
+/* Sets address and port in struct sockaddr_storage *sa
+ */
+static void
+sockaddr(struct sockaddr_storage *sa, int af, void *addr, int port)
+{
+        struct sockaddr_in *sin4;
+        struct sockaddr_in6 *sin6;
+
+        bzero(sa, sizeof *sa);
+        switch (af) {
+        case AF_INET:
+                sin4 = (struct sockaddr_in *)sa;
+                sin4->sin_len = sizeof *sin4;
+                sin4->sin_family = af;
+                sin4->sin_port = port;
+                sin4->sin_addr = *(struct in_addr *)addr;
+                break;
+        case AF_INET6:
+                sin6 = (struct sockaddr_in6 *)sa;
+                sin6->sin6_len = sizeof *sin6;
+                sin6->sin6_family = af;
+                sin6->sin6_port = port;
+                sin6->sin6_addr = *(struct in6_addr *)addr;
+                break;
+        default:
+                return;
+        }
+}
+
+/* Get socket information from the kernel.
+ */
+static void
+gather_inet(int proto)
+{
+        struct xinpgen *xig, *exig;
+        struct xinpcb *xip;
+        struct xtcpcb *xtp;
+        struct inpcb *inp;
+        struct xsocket *so;
+        struct sock *sock;
+        char varname[32];
+        size_t len, bufsize, bufsize0;
+        void *buf;
+        int hash, retry, vflag;
+
+        vflag = 0;
+        if (opt_4)
+                vflag |= INP_IPV4;
+        if (opt_6)
+                vflag |= INP_IPV6;
+
+        switch (proto) {
+        case IPPROTO_TCP:
+	  sl_strlcpy(varname, _("net.inet.tcp.pcblist"), sizeof(varname));
+                break;
+        case IPPROTO_UDP:
+                sl_strlcpy(varname, _("net.inet.udp.pcblist"), sizeof(varname));
+                break;
+        case IPPROTO_DIVERT:
+                sl_strlcpy(varname, _("net.inet.divert.pcblist"), sizeof(varname));
+                break;
+        default:
+                return;
+        }
+
+        buf = NULL;
+        bufsize  = 8192;
+	bufsize0 = bufsize;
+        retry = 5;
+        do {
+                for (;;) {
+		        buf = xrealloc(buf, bufsize0, bufsize);
+			bufsize0 = bufsize;
+                        len = bufsize;
+                        if (sysctlbyname(varname, buf, &len, NULL, 0) == 0)
+                                break;
+                        if (errno == ENOENT)
+                                goto out;
+                        if (errno != ENOMEM)
+			  {
+			    SH_MUTEX_LOCK(mutex_thread_nolog);
+			    sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN, 
+					    _("sysctlbyname()"), 
+					    _("gather_inet"));
+			    SH_MUTEX_UNLOCK(mutex_thread_nolog);
+			    return;
+			  }
+                        bufsize *= 2;
+                }
+                xig = (struct xinpgen *)buf;
+                exig = (struct xinpgen *)(void *)
+                    ((char *)buf + len - sizeof *exig);
+                if (xig->xig_len != sizeof *xig ||
+                    exig->xig_len != sizeof *exig)
+		  {
+		    SH_MUTEX_LOCK(mutex_thread_nolog);
+		    sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN, 
+				    _("struct xinpgen size mismatch"), 
+				    _("gather_inet"));
+		    SH_MUTEX_UNLOCK(mutex_thread_nolog);
+		    goto out;
+		  }
+
+        } while (xig->xig_gen != exig->xig_gen && retry--);
+
+        if (xig->xig_gen != exig->xig_gen && opt_v)
+		  {
+		    SH_MUTEX_LOCK(mutex_thread_nolog);
+		    sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN, 
+				    _("data may be inconsistent"), 
+				    _("gather_inet"));
+		    SH_MUTEX_UNLOCK(mutex_thread_nolog);
+		  }
+
+        for (;;) {
+                xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len);
+                if (xig >= exig)
+                        break;
+                switch (proto) {
+                case IPPROTO_TCP:
+                        xtp = (struct xtcpcb *)xig;
+                        if (xtp->xt_len != sizeof *xtp) {
+				SH_MUTEX_LOCK(mutex_thread_nolog);
+				sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN, 
+						_("struct xtcpcb size mismatch"), 
+						_("gather_inet"));
+				SH_MUTEX_UNLOCK(mutex_thread_nolog);
+                                goto out;
+                        }
+                        inp = &xtp->xt_inp;
+                        so = &xtp->xt_socket;
+                        break;
+                case IPPROTO_UDP:
+                case IPPROTO_DIVERT:
+                        xip = (struct xinpcb *)xig;
+                        if (xip->xi_len != sizeof *xip) {
+				SH_MUTEX_LOCK(mutex_thread_nolog);
+				sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN, 
+						_("struct xinpcb size mismatch"), 
+						_("gather_inet"));
+				SH_MUTEX_UNLOCK(mutex_thread_nolog);
+                                goto out;
+                        }
+                        inp = &xip->xi_inp;
+                        so = &xip->xi_socket;
+                        break;
+                default:
+                        return;
+                }
+                if ((inp->inp_vflag & vflag) == 0)
+                        continue;
+                if (inp->inp_vflag & INP_IPV4) {
+                        if ((inp->inp_fport == 0 && !opt_l) ||
+                            (inp->inp_fport != 0 && !opt_c))
+                                continue;
+                } else if (inp->inp_vflag & INP_IPV6) {
+                        if ((inp->in6p_fport == 0 && !opt_l) ||
+                            (inp->in6p_fport != 0 && !opt_c))
+                                continue;
+                } else {
+		        if (opt_v) {
+			        char errmsg[64];
+                                sl_snprintf(errmsg, sizeof(errmsg), 
+					    _("invalid vflag 0x%x"), inp->inp_vflag);
+				SH_MUTEX_LOCK(mutex_thread_nolog);
+				sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN, 
+						errmsg, 
+						_("gather_inet"));
+				SH_MUTEX_UNLOCK(mutex_thread_nolog);
+				continue;
+			}
+                }
+
+                sock = SH_ALLOC(sizeof *sock);
+		memset(sock, '\0', sizeof (*sock));
+
+                sock->socket = so->xso_so;
+                sock->proto = proto;
+                if (inp->inp_vflag & INP_IPV4) {
+                        sock->family = AF_INET;
+                        sockaddr(&sock->laddr, sock->family,
+                            &inp->inp_laddr, inp->inp_lport);
+                        sockaddr(&sock->faddr, sock->family,
+                            &inp->inp_faddr, inp->inp_fport);
+                } else if (inp->inp_vflag & INP_IPV6) {
+                        sock->family = AF_INET6;
+                        sockaddr(&sock->laddr, sock->family,
+                            &inp->in6p_laddr, inp->in6p_lport);
+                        sockaddr(&sock->faddr, sock->family,
+                            &inp->in6p_faddr, inp->in6p_fport);
+                }
+                sock->vflag = inp->inp_vflag;
+
+                hash = (int)((uintptr_t)sock->socket % HASHSIZE);
+                sock->next = sockhash[hash];
+                sockhash[hash] = sock;
+        }
+out:
+        free(buf);
+}
+
+static void
+getfiles(void)
+{
+        size_t len;
+        size_t len0;
+
+        xfiles = SH_ALLOC(len = sizeof *xfiles);
+	len0   = len;
+
+        while (sysctlbyname(_("kern.file"), xfiles, &len, 0, 0) == -1) {
+                if (errno != ENOMEM)
+		  {
+		    SH_MUTEX_LOCK(mutex_thread_nolog);
+		    sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
+				    _("sysctlbyname()"),
+				    _("getfiles"));
+		    SH_MUTEX_UNLOCK(mutex_thread_nolog);
+		  }
+                len *= 2;
+                xfiles = xrealloc(xfiles, len0, len);
+		len0   = len;
+        }
+        if (len > 0 && xfiles->xf_size != sizeof *xfiles)
+                if (errno != ENOMEM)
+		  {
+		    SH_MUTEX_LOCK(mutex_thread_nolog);
+		    sh_error_handle((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
+				    _("struct xfile size mismatch"),
+				    _("getfiles"));
+		    SH_MUTEX_UNLOCK(mutex_thread_nolog);
+		  }
+        nxfiles = len / sizeof *xfiles;
+}
+
+static const char *
+getprocname(pid_t pid)
+{
+        static struct kinfo_proc proc;
+        size_t len;
+        int mib[4];
+
+        mib[0] = CTL_KERN;
+        mib[1] = KERN_PROC;
+        mib[2] = KERN_PROC_PID;
+        mib[3] = (int)pid;
+        len = sizeof proc;
+        if (sysctl(mib, 4, &proc, &len, NULL, 0) == -1) {
+                /* Do not warn if the process exits before we get its name. */
+                if (errno != ESRCH)
+		  {
+		    SH_MUTEX_LOCK(mutex_thread_nolog);
+		    sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, status, MSG_E_SUBGEN,
+				    _("sysctl()"),
+				    _("getfiles"));
+		    SH_MUTEX_UNLOCK(mutex_thread_nolog);
+		  }
+                return ("-");
+        }
+        return (proc.ki_ocomm);
+}
+
+char * sh_port2proc_query(int proto, struct in_addr * saddr, int sport,
+			  char * user, size_t userlen)
+{
+  struct xfile *xf;
+  struct in_addr * haddr;
+  
+  for (xf = xfiles, n = 0; n < nxfiles; ++n, ++xf) {
+    
+    if (xf->xf_data == NULL)
+      continue;
+    
+    /* Find the socket in sockhash[] that corresponds to it
+     */
+    hash = (int)((uintptr_t)xf->xf_data % HASHSIZE);
+    for (s = sockhash[hash]; s != NULL; s = s->next)
+      if ((void *)s->socket == xf->xf_data)
+	break;
+    
+    if (s->proto != proto)
+      continue;
+
+    if (s->family != AF_INET /* && s->family != AF_INET6 */)
+      continue;
+
+    if (sport != ntohs(((struct sockaddr_in *)s)->sin_port))
+      continue;
+
+    haddr = &((struct sockaddr_in *)s)->sin_addr;
+    if (haddr.s_addr == saddr->s_addr)
+      {
+	char * tmp  = sh_unix_getUIDname (SH_ERR_ALL, xf->xf_uid, user, userlen);
+	if (!tmp)
+	  sl_snprintf (user, userlen, "%ld", (unsigned long) xf->xf_uid);
+	return sh_util_strdup(getprocname(xf->xf_pid));
+      }
+  }
+}
+
+static void sockdel(struct sock * sock)
+{
+  if (sock)
+    {
+      if (sock->next)
+	sockdel(sock->next);
+      SH_FREE(sock);
+    }
+  return;
+}
+
+int sh_port2proc_prepare()
+{
+  int i;
+
+  if (xfiles)
+    {
+      SH_FREE(xfiles);
+      xfiles = NULL;
+    }
+
+  for (i = 0; i < HASHSIZE; ++i)
+    sockdel(sockhash[i]);
+
+  /* Inet connections
+   */
+  gather_inet(IPPROTO_TCP);
+  gather_inet(IPPROTO_UDP);
+  gather_inet(IPPROTO_DIVERT);
+
+  getfiles();
+
+  return 0;
+}
+
+#else /* !defined(__linux__) && !defined(__FreeBSD__) */
 
 char * sh_port2proc_query(int proto, struct in_addr * saddr, int sport,
