components/pflogd/patches/001-solaris.patch
author Rich Burridge <rich.burridge@oracle.com>
Wed, 20 Apr 2016 19:46:50 -0700
changeset 5826 9c90e4a8156c
parent 5565 f678cc44b3d0
child 7791 95f8368a21ec
permissions -rw-r--r--
23137909 Userland man page normalization work

# This patch comes from Oracle. It fixes issues preventing pflogd
# from building and running on Solaris. Especially, we:
# - make it read packets from Solaris-specific capture links instead
#   of OpenBSD's pflog interfaces
# - introduce our own pcap_pkthdr structure as the one used by
#   upstream would result in corrupted packet dump files on Solaris
# - use Solaris-specific random number generator
#
# This patch is not going to upstream, the changes are Solaris-specific.

diff -Naur ORIGINAL/Makefile pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/Makefile
--- ORIGINAL/Makefile	2013-06-18 20:51:30.000000000 -0700
+++ pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/Makefile	2016-02-17 02:08:53.410106245 -0800
@@ -1,15 +1,28 @@
 #	$OpenBSD: Makefile,v 1.9 2013/06/19 03:51:30 lteo Exp $
 
-CFLAGS+=-Wall -Wmissing-prototypes -Wshadow
+CFLAGS+= -m64 -errwarn
 
-# for pcap-int.h
-CFLAGS+=-I${.CURDIR}/../../lib/libpcap
+PROG=pflogd
+SRCS=pflogd.c privsep.c privsep_fdpass.c
+OBJS=$(SRCS:.c=.o)
+MAN=pflogd.8
 
-LDADD+= -lpcap
-DPADD+=	${LIBPCAP}
+LDADD+=-lpcap -ldladm -luutil
 
-PROG=	pflogd
-SRCS=	pflogd.c privsep.c privsep_fdpass.c
-MAN=	pflogd.8
+all:	$(SRCS) $(PROG)
 
-.include <bsd.prog.mk>
+install: $(PROG)
+	$(INSTALL) -d $(PREFIX)/sbin
+	$(INSTALL) -m 755 $(PROG) $(PREFIX)/sbin
+	$(INSTALL) -d $(MANDIR)/man8
+	$(INSTALL) -m 644 $(MAN) $(MANDIR)/man8
+
+$(PROG):	$(OBJS)
+	$(CC) $(CFLAGS) $(OBJS) -o $@ $(LDADD)
+
+.c.o:
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+clean:
+	rm -rf *.o
+	rm -rf $(PROG)
diff -Naur ORIGINAL/pflogd.8 pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/pflogd.8
--- ORIGINAL/pflogd.8	2014-01-20 19:15:45.000000000 -0800
+++ pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/pflogd.8	2016-02-17 02:32:29.857912548 -0800
@@ -44,15 +44,15 @@
 .Nm
 is a background daemon which reads packets logged by
 .Xr pf 4
-to a
-.Xr pflog 4
-interface, normally
+to a dedicated capture link interface (see
+.Xr dladm 1M
+for details), normally
 .Pa pflog0 ,
 and writes the packets to a logfile (normally
-.Pa /var/log/pflog )
-in
-.Xr tcpdump 8
-binary format.
+.Pa /var/log/firewall/pflog/pflog0.pkt )
+in libpcap format (see
+.Xr PCAP 3pcap
+for details).
 These logs can be reviewed later using the
 .Fl r
 option of
@@ -63,9 +63,7 @@
 .Nm
 closes and then re-opens the log file when it receives
 .Dv SIGHUP ,
-permitting
-.Xr newsyslog 8
-to rotate logfiles automatically.
+permitting convenient log rotation.
 .Dv SIGALRM
 causes
 .Nm
@@ -96,7 +94,7 @@
 .Pp
 .Nm
 will also log the pcap statistics for the
-.Xr pflog 4
+capture link
 interface to syslog when a
 .Dv SIGUSR1
 is received.
@@ -113,12 +111,8 @@
 If not specified, the default is 60 seconds.
 .It Fl f Ar filename
 Log output filename.
-Default is
-.Pa /var/log/pflog .
 .It Fl i Ar interface
-Specifies the
-.Xr pflog 4
-interface to use.
+Specifies the capture link interface to use.
 By default,
 .Nm
 will use
@@ -172,7 +166,7 @@
 .El
 .Sh FILES
 .Bl -tag -width /var/run/pflogd.pid -compact
-.It Pa /var/log/pflog
+.It Pa /var/log/firewall/pflog/pflog0.pkt
 Default log file.
 .El
 .Sh EXAMPLES
@@ -185,7 +179,7 @@
 .Ed
 .Pp
 Log from another
-.Xr pflog 4
+capture link
 interface, excluding specific packets:
 .Bd -literal -offset indent
 # pflogd -i pflog3 -f network3.log "not (tcp and port 23)"
@@ -193,7 +187,7 @@
 .Pp
 Display binary logs:
 .Bd -literal -offset indent
-# tcpdump -n -e -ttt -r /var/log/pflog
+# tcpdump -n -e -ttt -r /var/log/firewall/pflog/pflog3.pkt
 .Ed
 .Pp
 Display the logs in real time (this does not interfere with the
@@ -210,16 +204,18 @@
 .Ed
 .Sh SEE ALSO
 .Xr pcap 3 ,
-.Xr pf 4 ,
-.Xr pflog 4 ,
 .Xr pf.conf 5 ,
-.Xr newsyslog 8 ,
+.Xr privileges 7 ,
+.Xr smf 7 ,
 .Xr tcpdump 8
 .Sh HISTORY
 The
 .Nm
 command appeared in
 .Ox 3.0 .
+The Solaris version is based on
+.Nm
+found in OpenBSD 5.5.
 .Sh AUTHORS
 .Nm
 was written by
diff -Naur ORIGINAL/pflogd.c pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/pflogd.c
--- ORIGINAL/pflogd.c	2012-11-05 18:50:47.000000000 -0800
+++ pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/pflogd.c	2016-02-18 12:05:03.256562087 -0800
@@ -48,7 +48,15 @@
 #include <errno.h>
 #include <stdarg.h>
 #include <fcntl.h>
+#ifdef	_SOLARIS_
+#include <libdladm.h>
+#include <libnetcfg.h>
+#include <strings.h>
+#include <zone.h>
+#include <libuutil.h>
+#else /* !_SOLARIS_ */
 #include <util.h>
+#endif	/* _SOLARIS_ */
 #include "pflogd.h"
 
 pcap_t *hpcap;
@@ -88,6 +96,34 @@
 void  sig_hup(int);
 void  usage(void);
 
+#ifdef	_SOLARIS_
+/*
+ * setproctitle() is found in libc on OpenBSD. It allows program to update its
+ * process name. It will be an empty macro on Solaris.
+ */
+#define	setproctitle(...)
+
+/*
+ * __dead attribute will be an empty macro on Solaris.
+ */
+#define	__dead
+
+/*
+ * We must define our own pcap_pkthdr to ensure timeval structure will be
+ * defined in 32-bit version. Not doing so will result in corrupted packet dump
+ * file produced by pflogd on Solaris.
+ */
+typedef struct pcap_pkthdr_file {
+	struct {
+		uint32_t	tv_sec;
+		uint32_t	tv_usec;
+	} ts;
+	uint32_t	caplen;
+	uint32_t	len;
+} pcap_pkthdr_file_t;
+
+#endif	/* _SOLARIS_ */
+
 static int try_reset_dump(int);
 
 /* buffer must always be greater than snaplen */
@@ -191,11 +227,13 @@
 {
 	struct bpf_program bprog;
 
-	if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0)
+	if (pcap_compile(hpcap, &bprog, filter, PCAP_OPT_FIL, 0) < 0) {
 		logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
-	else {
+		logmsg(LOG_WARNING, "for filter:\n\t%s\nNo filter set.\n", filter);
+	} else {
 		if (pcap_setfilter(hpcap, &bprog) < 0)
-			logmsg(LOG_WARNING, "%s", pcap_geterr(hpcap));
+			logmsg(LOG_WARNING, "%s\nNo filter set.\n",
+			    pcap_geterr(hpcap));
 		pcap_freecode(&bprog);
 	}
 }
@@ -203,6 +241,31 @@
 int
 if_exists(char *ifname)
 {
+#ifdef	_SOLARIS_
+	dladm_handle_t	dlh;
+	datalink_id_t	linkid;
+	zoneid_t	zid = getzoneid();
+	dladm_status_t	dls;
+	int		rv = 0;
+
+	if (!dladm_valid_linkname(ifname) ||
+	    (dladm_open(&dlh) != DLADM_STATUS_OK)) {
+		errno = ENXIO;
+		return (rv);
+	}
+
+	dls = dladm_apply_linknamefilters(dlh, ifname, &linkid, 1, &zid,
+	    DLADM_OPT_ACTIVE, zid, NULL);
+	if ((dls == DLADM_STATUS_OK) && (linkid != DATALINK_INVALID_LINKID)) {
+		rv = 1;
+	}
+
+	dladm_close(dlh);
+
+	errno = (rv == 1) ? 0 : ENXIO;
+
+	return (rv);
+#else /* !_SOLARIS_ */
 	int s, ret = 1;
 	struct ifreq ifr;
 	struct if_data ifrdat;
@@ -220,6 +283,7 @@
 		err(1, "close");
 
 	return (ret);
+#endif	/* _SOLARIS_ */
 }
 
 int
@@ -243,10 +307,15 @@
 	cur_snaplen = snaplen = pcap_snapshot(hpcap);
 
 	/* lock */
+/*
+ * BIOCLOCK operation is not implmented on Solaris. 
+ */
+#ifndef	_SOLARIS_
 	if (ioctl(pcap_fileno(hpcap), BIOCLOCK) < 0) {
 		logmsg(LOG_ERR, "BIOCLOCK: %s", strerror(errno));
 		return (-1);
 	}
+#endif	/* !_SOLARIS_ */
 
 	return (0);
 }
@@ -371,7 +440,11 @@
 scan_dump(FILE *fp, off_t size)
 {
 	struct pcap_file_header hdr;
+#ifdef	_SOLARIS_
+	struct pcap_pkthdr_file	ph;
+#else /* !_SOLARIS_ */
 	struct pcap_pkthdr ph;
+#endif	/* _SOLARIS_ */
 	off_t pos;
 
 	/*
@@ -440,13 +513,26 @@
 dump_packet_nobuf(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
 {
 	FILE *f = (FILE *)user;
+#ifdef	_SOLARIS_
+	struct pcap_pkthdr_file	h_file;
+#endif	/* _SOLARIS_ */
 
 	if (suspended) {
 		packets_dropped++;
 		return;
 	}
 
-	if (fwrite((char *)h, sizeof(*h), 1, f) != 1) {
+#ifdef	_SOLARIS_
+	h_file.ts.tv_sec = (uint32_t)h->ts.tv_sec;
+	h_file.ts.tv_usec = (uint32_t)h->ts.tv_usec;
+	h_file.caplen = h->caplen;
+	h_file.len = h->len;
+	if (fwrite((char *)&h_file, sizeof (h_file), 1, f) != 1)
+#else	/* !_SOLARIS_ */
+	if (fwrite((char *)h, sizeof(*h), 1, f) != 1)
+#endif	/* _SOLARIS_ */
+
+	{
 		off_t pos = ftello(f);
 
 		/* try to undo header to prevent corruption */
@@ -520,9 +606,32 @@
 dump_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
 {
 	FILE *f = (FILE *)user;
+#ifdef	_SOLARIS_
+	struct pcap_pkthdr_file	h_file;
+	size_t len = sizeof (h_file) + h->caplen;
+#else	/* !_SOLARIS_ */
 	size_t len = sizeof(*h) + h->caplen;
+#endif	/* _SOLARIS_ */
 
-	if (len < sizeof(*h) || h->caplen > (size_t)cur_snaplen) {
+#ifdef	_SOLARIS_
+	/*
+	 * Member ts is struct timeval defined in sys/time.h. Solaris uses
+	 * 64-bit version for tv_sec, tv_usec. 64-bit members are not
+	 * compatible with pcap file format, hence we must convert them to
+	 * 32-bits.
+	 */
+	h_file.ts.tv_sec = (uint32_t)h->ts.tv_sec;
+	h_file.ts.tv_usec = (uint32_t)h->ts.tv_usec;
+	h_file.caplen = h->caplen;
+	h_file.len = h->len;
+#endif	/* _SOLARIS_ */
+
+#ifdef	_SOLARIS_
+	if (len < sizeof(h_file) || h_file.caplen > (size_t)cur_snaplen)
+#else	/* !_SOLARIS_ */
+	if (len < sizeof(*h) || h->caplen > (size_t)cur_snaplen)
+#endif	/* _SOLARIS_ */
+	{
 		logmsg(LOG_NOTICE, "invalid size %zu (%d/%d), packet dropped",
 		       len, cur_snaplen, snaplen);
 		packets_dropped++;
@@ -548,8 +657,13 @@
 	}
 
  append:
+#ifdef	_SOLARIS_
+	(void) memcpy(bufpos, &h_file, sizeof (h_file));
+	(void) memcpy(bufpos + sizeof (h_file), sp, h->caplen);
+#else	/* !_SOLARIS_ */
 	memcpy(bufpos, h, sizeof(*h));
 	memcpy(bufpos + sizeof(*h), sp, h->caplen);
+#endif	/* _SOLARIS_ */
 
 	bufpos += len;
 	bufleft -= len;
@@ -611,7 +725,6 @@
 		default:
 			usage();
 		}
-
 	}
 
 	log_debug = Debug;
@@ -658,12 +771,25 @@
 
 	setproctitle("[initializing]");
 	/* Process is now unprivileged and inside a chroot */
+#ifdef	_SOLARIS_
+	/*
+	 * We have to use sigset() on Solaris, since signal() resets sig.
+	 * handler to default as soon as particular signal is delivered.
+	 */
+	sigset(SIGTERM, sig_close);
+	sigset(SIGINT, sig_close);
+	sigset(SIGQUIT, sig_close);
+	sigset(SIGALRM, sig_alrm);
+	sigset(SIGUSR1, sig_usr1);
+	sigset(SIGHUP, sig_hup);
+#else /* !_SOLARIS_ */
 	signal(SIGTERM, sig_close);
 	signal(SIGINT, sig_close);
 	signal(SIGQUIT, sig_close);
 	signal(SIGALRM, sig_alrm);
 	signal(SIGUSR1, sig_usr1);
 	signal(SIGHUP, sig_hup);
+#endif	/* _SOLARIS_ */
 	alarm(delay);
 
 	buffer = malloc(PFLOGD_BUFSIZE);
@@ -696,7 +822,7 @@
 				ret = -1;
 				break;
 			}
-			logmsg(LOG_NOTICE, "%s", pcap_geterr(hpcap));
+			logmsg(LOG_NOTICE, "pcap says: %s", pcap_geterr(hpcap));
 		}
 
 		if (gotsig_close)
diff -Naur ORIGINAL/pflogd.h pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/pflogd.h
--- ORIGINAL/pflogd.h	2010-09-20 22:56:58.000000000 -0700
+++ pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/pflogd.h	2016-02-18 12:08:42.414919276 -0800
@@ -16,7 +16,11 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#ifdef	_SOLARIS_
+#include <limits.h>
+#else /* !_SOLARIS_ */
 #include <sys/limits.h>
+#endif	/* _SOLARIS_ */
 #include <pcap.h>
 
 #define DEF_SNAPLEN 160		/* pfloghdr + ip hdr + proto hdr fit usually */
@@ -25,7 +29,12 @@
 #define PCAP_OPT_FIL 1		/* filter optimization */
 #define FLUSH_DELAY 60		/* flush delay */
 
+#ifdef	_SOLARIS_
+#define	PFLOGD_LOG_DIR		"/var/log/firewall/pflog"
+#define PFLOGD_LOG_FILE		"pflog.pkt"
+#else /* !_SOLARIS_ */
 #define PFLOGD_LOG_FILE		"/var/log/pflog"
+#endif	/* _SOLARIS_ */
 #define PFLOGD_DEFAULT_IF	"pflog0"
 
 #define PFLOGD_MAXSNAPLEN	INT_MAX
diff -Naur ORIGINAL/privsep.c pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/privsep.c
--- ORIGINAL/privsep.c	2013-09-13 01:49:17.000000000 -0700
+++ pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/privsep.c	2016-02-18 12:07:34.219667793 -0800
@@ -28,8 +28,6 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
-#include <pcap.h>
-#include <pcap-int.h>
 #include <pwd.h>
 #include <signal.h>
 #include <stdio.h>
@@ -38,6 +36,34 @@
 #include <syslog.h>
 #include <unistd.h>
 #include "pflogd.h"
+#ifdef	_SOLARIS_
+#include <priv.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <time.h>
+#include <sys/random.h>
+#endif	/* _SOLARIS_ */
+/*
+ * It's better to include these after other header files.
+ * pcap-int.h defines strlcpy() as macro if it is undefined.
+ * In our case strlcpy() comes from string.h.
+ */
+#define	HAVE_SNPRINTF	1
+#include <pcap.h>
+#include <pcap-int.h>
+
+#ifdef	_SOLARIS_
+#define	_NSIG	27
+
+/*
+ * setproctitle() is found in libc on OpenBSD. It allows program to update its
+ * process name. It will empty macro on Solaris.
+ */
+#define	setproctitle(...)
+
+#else /* !_SOLARIS_ */
+#define	PFLOGD_USER	"_pflogd"
+#endif	/* _SOLARIS_ */
 
 enum cmd_types {
 	PRIV_SET_SNAPLEN,	/* set the snaplength */
@@ -67,7 +93,9 @@
 {
 	int i, fd, socks[2], cmd;
 	int snaplen, ret, olderrno;
+#ifndef	_SOLARIS_
 	struct passwd *pw;
+#endif	/* !_SOLARIS_ */
 
 	for (i = 1; i < _NSIG; i++)
 		signal(i, SIG_DFL);
@@ -76,16 +104,19 @@
 	if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1)
 		err(1, "socketpair() failed");
 
+#ifndef	_SOLARIS_
 	pw = getpwnam("_pflogd");
 	if (pw == NULL)
 		errx(1, "unknown user _pflogd");
 	endpwent();
+#endif	/* !_SOLARIS_ */
 
 	child_pid = fork();
 	if (child_pid < 0)
 		err(1, "fork() failed");
 
 	if (!child_pid) {
+#ifndef	_SOLARIS_
 		gid_t gidset[1];
 
 		/* Child - drop privileges and return */
@@ -101,6 +132,8 @@
 			err(1, "setgroups() failed");
 		if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
 			err(1, "setresuid() failed");
+#endif	/* !_SOLARIS_ */
+
 		close(socks[0]);
 		priv_fd = socks[1];
 		return 0;
@@ -108,19 +141,34 @@
 
 	/* Father */
 	/* Pass ALRM/TERM/HUP/INT/QUIT through to child, and accept CHLD */
+#ifdef	_SOLARIS_
+	/*
+	 * We have to use sigset() on Solaris, since signal() resets sig.
+	 * handler to default as soon as particular signal is delivered.
+	 */
+	sigset(SIGALRM, sig_pass_to_chld);
+	sigset(SIGTERM, sig_pass_to_chld);
+	sigset(SIGHUP,  sig_pass_to_chld);
+	sigset(SIGINT,  sig_pass_to_chld);
+	sigset(SIGQUIT,  sig_pass_to_chld);
+	sigset(SIGCHLD, sig_chld);
+#else /* !_SOLARIS_ */
 	signal(SIGALRM, sig_pass_to_chld);
 	signal(SIGTERM, sig_pass_to_chld);
 	signal(SIGHUP,  sig_pass_to_chld);
 	signal(SIGINT,  sig_pass_to_chld);
 	signal(SIGQUIT,  sig_pass_to_chld);
 	signal(SIGCHLD, sig_chld);
+#endif	/* _SOLARIS_ */
 
 	setproctitle("[priv]");
 	close(socks[1]);
 
 	while (!gotsig_chld) {
-		if (may_read(socks[0], &cmd, sizeof(int)))
+		if (may_read(socks[0], &cmd, sizeof(int))) {
+			logmsg(LOG_ERR, "may_read: fails\n");
 			break;
+		}
 		switch (cmd) {
 		case PRIV_SET_SNAPLEN:
 			logmsg(LOG_DEBUG,
@@ -192,9 +240,20 @@
 
 	for (;;) {
 		int fd;
+#ifdef _SOLARIS_
+		uint32_t rand;
 
+		if (getrandom(&rand, sizeof (rand), GRND_NONBLOCK) !=
+		    sizeof (rand)) {
+			logmsg(LOG_ERR, "getrandom() failed");
+			return 1;
+		}
+		len = snprintf(ren, sizeof(ren), "%s.bad.%08x",
+		    name, rand);
+#else /* !_SOLARIS_ */
 		len = snprintf(ren, sizeof(ren), "%s.bad.%08x",
 		    name, arc4random());
+#endif /* _SOLARIS_ */
 		if (len >= sizeof(ren)) {
 			logmsg(LOG_ERR, "[priv] new name too long");
 			return (1);