components/pflogd/patches/001-solaris.patch
branchs11u3-sru
changeset 7575 2e0470f8f10d
child 7893 42bd065fc5bc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/pflogd/patches/001-solaris.patch	Fri Jan 13 13:12:57 2017 -0800
@@ -0,0 +1,584 @@
+# 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.
+
+--- ORIGINAL/./Makefile	2013-06-18 20:51:30.000000000 -0700
++++ pflogd-OPENBSD_5_5.pre-smf/./Makefile	2016-09-23 13:05:27.779789350 -0700
+@@ -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 -lsocket
+ 
+-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)
+--- ORIGINAL/./pflogd.8	2014-01-20 19:15:45.000000000 -0800
++++ pflogd-OPENBSD_5_5.pre-smf/./pflogd.8	2016-09-23 13:05:27.780237460 -0700
+@@ -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
+--- ORIGINAL/./pflogd.c	2012-11-05 18:50:47.000000000 -0800
++++ pflogd-OPENBSD_5_5.pre-smf/./pflogd.c	2016-09-23 13:05:27.780857317 -0700
+@@ -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, NULL) != 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)
+--- ORIGINAL/./pflogd.h	2010-09-20 22:56:58.000000000 -0700
++++ pflogd-OPENBSD_5_5.pre-smf/./pflogd.h	2016-09-23 13:05:27.781083183 -0700
+@@ -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
+--- ORIGINAL/./privsep.c	2013-09-13 01:49:17.000000000 -0700
++++ pflogd-OPENBSD_5_5.pre-smf/./privsep.c	2016-09-23 13:05:27.781439350 -0700
+@@ -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);