components/pflogd/patches/002-smf.patch
author Alan Coopersmith <Alan.Coopersmith@Oracle.COM>
Tue, 04 Apr 2017 17:27:12 -0700
changeset 7830 a19af6ab1a9c
parent 5826 9c90e4a8156c
permissions -rw-r--r--
25816799 Remove more excess FOSS from Desktop gate [PSARC 2016/088 - b122 subset] PSARC/2016/088 EOF of more excess FOSS from Desktop consolidation (scrubbing the decks harder)

# This patch comes from Oracle. It turns the component into
# a well-behaving SMF service. It adds code manipulating service
# properties, service instances, and also provides security
# in cooperation with the service manifest (especially, extra
# privileges are dropped when not needed).
#
# This patch is not going to upstream, the changes are Solaris-specific.

diff -Naur pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/Makefile pflogd-OPENBSD_5_5-OPENBSD_5_5/Makefile
--- pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/Makefile	2016-02-17 02:08:53.410106245 -0800
+++ pflogd-OPENBSD_5_5-OPENBSD_5_5/Makefile	2016-02-16 05:02:32.489035397 -0800
@@ -3,7 +3,7 @@
 CFLAGS+= -m64 -errwarn
 
 PROG=pflogd
-SRCS=pflogd.c privsep.c privsep_fdpass.c
+SRCS=pflogd.c privsep.c privsep_fdpass.c smf-config.c
 OBJS=$(SRCS:.c=.o)
 MAN=pflogd.8
 
diff -Naur pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/pflogd.8 pflogd-OPENBSD_5_5-OPENBSD_5_5/pflogd.8
--- pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/pflogd.8	2016-02-17 02:32:29.857912548 -0800
+++ pflogd-OPENBSD_5_5-OPENBSD_5_5/pflogd.8	2016-03-14 07:10:13.031600727 -0700
@@ -33,7 +33,7 @@
 .Sh SYNOPSIS
 .Nm pflogd
 .Bk -words
-.Op Fl "Dx"
+.Op Fl C Ar new-pflog-instance-name | Fl c Ar pflog-instance-name
 .Op Fl d Ar delay
 .Op Fl f Ar filename
 .Op Fl i Ar interface
@@ -60,6 +60,7 @@
 hopefully offline in case there are bugs in the packet parsing code of
 .Xr tcpdump 8 .
 .Pp
+
 .Nm
 closes and then re-opens the log file when it receives
 .Dv SIGHUP ,
@@ -101,22 +102,52 @@
 .Pp
 The options are as follows:
 .Bl -tag -width Ds
-.It Fl D
-Debugging mode.
+.It Fl C Ar new-pflog-instance-name
+Creates a new
 .Nm
-does not disassociate from the controlling terminal.
+instance with the specified name. If additional options are used to specify
+configuration, it is stored into the
+.Xr smf 7
+repository. Default values are used for
+.Xr smf 7
+properties unless overriden by a command-line option. The exception is
+pflog/interface (set to equal the instance name) and pflog/logfile
+(set to a file with name equal to the instance name followed by the
+.Pa .pkt
+extension located inside the
+.Pa /var/log/firewall/pflog/
+directory) if the service instance name forms a valid linkname. If the
+service instance name is not a valid linkname, the values must be
+given explicitly.
+.It Fl c Ar pflog-instance-name
+Shows/changes the configuration of the given
+.Nm
+instance in
+.Xr smf 7
+repository. Attributes specified by additional options are placed into the
+.Xr smf 7
+repository.
 .It Fl d Ar delay
 Time in seconds to delay between automatic flushes of the file.
 This may be specified with a value between 5 and 3600 seconds.
 If not specified, the default is 60 seconds.
 .It Fl f Ar filename
-Log output filename.
+Log output filename. When neither
+.Fl C
+nor
+.Fl c
+is used, the default value
+.Pa pflog.pkt
+is used.
 .It Fl i Ar interface
 Specifies the capture link interface to use.
-By default,
-.Nm
-will use
-.Pa pflog0 .
+When neither
+.Fl C
+nor
+.Fl c
+is used, the default value
+.Pa pflog0
+is assumed.
 .It Fl s Ar snaplen
 Analyze at most the first
 .Ar snaplen
@@ -124,8 +155,6 @@
 The default of 160 is adequate for IP, ICMP, TCP, and UDP headers but may
 truncate protocol information for other protocols.
 Other file parsers may desire a higher snaplen.
-.It Fl x
-Check the integrity of an existing log file, and return.
 .It Ar expression
 Selects which packets will be dumped, using the regular language of
 .Xr tcpdump 8 .
@@ -164,11 +193,59 @@
 The direction was outbound.
 .El
 .El
-.Sh FILES
-.Bl -tag -width /var/run/pflogd.pid -compact
-.It Pa /var/log/firewall/pflog/pflog0.pkt
-Default log file.
+.Sh SOLARIS
+The
+.Nm
+daemon must be started as an
+.Xr smf 7
+service with the following FMRI:
+.Bd -literal -offset indent
+svc:/network/firewall/pflog
+.Ed
+.Pp
+Command line options described above are set via the following
+.Xr smf 7
+properties.
+.Bl -tag -width "pflog/interface" -offset 3n -compact
+.It pflog/delay
+Automatic flush interval.
+The default value is 60.
+Used as the argument for the
+.Fl d
+option.
+.It pflog/filter
+Packet filter expression in
+.Xr tcpdump 8
+format.
+No expression is defined by default.
+.It pflog/interface
+The capture link name from which to read packets.
+Used as the argument for the
+.Fl i
+option.
+.It pflog/logfile
+Path to the logfile (for security reasons, only paths starting by the
+.Pa /var/log/firewall/
+directory are allowed.
+Used as the argument for the
+.Fl f
+option.
+.It pflog/snaplen
+An upper bound on how many bytes from each packet to analyze.
+The default value is 160.
+Used as the argument for the
+.Fl s
+option.
 .El
+.Pp
+The start method creates a (temporal) capture link the particular
+instance is using.
+.Pp
+The refresh method sends
+.Dv SIGHUP
+to
+.Nm
+owned by particular service instance.
 .Sh EXAMPLES
 Log specific TCP packets to a different log file with a large snaplen
 (useful with a
@@ -202,6 +279,32 @@
 .Bd -literal -offset indent
 # tcpdump -n -e -ttt -i pflog0 inbound and action block and on wi0
 .Ed
+.Sh SECURITY
+The
+.Nm
+daemon is a privilege-aware application which runs as the
+.Dq daemon
+user possessing
+.Sy PRIV_NET_OBSERVABILITY
+privilege that is required for using
+.Xr bpf 7d
+to read packets. See
+.Xr privileges 7
+for details.
+The service start method uses
+.Xr dladm 8
+to create capture link if it does not exist already.
+.Pp
+To configure the
+.Nm
+service one has to obtain the
+.Sy solaris.smf.value.network.firewall
+authorization.
+To manage the service (disable/enable/refresh) one must have the
+.Sy solaris.smf.manage.network.firewall
+authorization.
+Both authorizations are granted through the Network Firewall Management profile.
+To create new service instances, you need the solaris.smf.modify authorization.
 .Sh SEE ALSO
 .Xr pcap 3 ,
 .Xr pf.conf 5 ,
diff -Naur pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/pflogd.c pflogd-OPENBSD_5_5-OPENBSD_5_5/pflogd.c
--- pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/pflogd.c	2016-02-18 12:05:03.256562087 -0800
+++ pflogd-OPENBSD_5_5-OPENBSD_5_5/pflogd.c	2016-02-18 12:01:49.900876863 -0800
@@ -54,6 +54,7 @@
 #include <strings.h>
 #include <zone.h>
 #include <libuutil.h>
+#include "smf-config.h"
 #else /* !_SOLARIS_ */
 #include <util.h>
 #endif	/* _SOLARIS_ */
@@ -63,7 +64,7 @@
 static FILE *dpcap;
 
 int Debug = 0;
-static int snaplen = DEF_SNAPLEN;
+static int64_t snaplen = DEF_SNAPLEN;
 static int cur_snaplen = DEF_SNAPLEN;
 
 volatile sig_atomic_t gotsig_close, gotsig_alrm, gotsig_hup, gotsig_usr1;
@@ -75,7 +76,7 @@
 char errbuf[PCAP_ERRBUF_SIZE];
 
 int log_debug = 0;
-unsigned int delay = FLUSH_DELAY;
+int64_t delay = FLUSH_DELAY;
 
 char *copy_argv(char * const *);
 void  dump_packet(u_char *, const struct pcap_pkthdr *, const u_char *);
@@ -124,6 +125,15 @@
 
 #endif	/* _SOLARIS_ */
 
+#ifdef	_SOLARIS_
+#define	PFLOGD_GETOPTS	"c:C:Dd:f:i:s:"
+#define	CFG_SETFLAG(_flags_, _f_)	((_flags_) |= (_f_))
+#define	SKIP_CHK(_x_)	((_x_) == NULL)
+#else /* !_SOLARIS_ */
+#define	PFLOGD_GETOPTS	"Dxd:f:i:s:"
+#define	CFG_SETFLAG(_flags_, _f_)
+#define	SKIP_CHK(_x_)	(1)
+#endif	/* _SOLARIS_ */
 static int try_reset_dump(int);
 
 /* buffer must always be greater than snaplen */
@@ -290,6 +300,8 @@
 init_pcap(void)
 {
 	hpcap = pcap_open_live(interface, snaplen, 1, PCAP_TO_MS, errbuf);
+	DROP_PRIV(PRIV_NET_OBSERVABILITY);
+
 	if (hpcap == NULL) {
 		logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
 		return (-1);
@@ -690,12 +702,20 @@
 	int ch, np, ret, Xflag = 0;
 	pcap_handler phandler = dump_packet;
 	const char *errstr = NULL;
+#ifdef	_SOLARIS_
+	unsigned int	create = 0;
+	unsigned int	cfg_flags = 0;
+	const char	*smf_instance = NULL;
+#endif	/* _SOLARIS_ */
+
+	DROP_PRIV(PRIV_SYS_IP_CONFIG);
+	DROP_PRIV(PRIV_PROC_EXEC);
 
 	ret = 0;
 
 	closefrom(STDERR_FILENO + 1);
 
-	while ((ch = getopt(argc, argv, "Dxd:f:i:s:")) != -1) {
+	while ((ch = getopt(argc, argv, PFLOGD_GETOPTS)) != -1) {
 		switch (ch) {
 		case 'D':
 			Debug = 1;
@@ -704,12 +724,15 @@
 			delay = strtonum(optarg, 5, 60*60, &errstr);
 			if (errstr)
 				usage();
+			CFG_SETFLAG(cfg_flags, SMF_CFG_DELAY_SET);
 			break;
 		case 'f':
 			filename = optarg;
+			CFG_SETFLAG(cfg_flags, SMF_CFG_LOGFILE_SET);
 			break;
 		case 'i':
 			interface = optarg;
+			CFG_SETFLAG(cfg_flags, SMF_CFG_INTERFACE_SET);
 			break;
 		case 's':
 			snaplen = strtonum(optarg, 0, PFLOGD_MAXSNAPLEN,
@@ -718,10 +741,27 @@
 				snaplen = DEF_SNAPLEN;
 			if (errstr)
 				snaplen = PFLOGD_MAXSNAPLEN;
+			CFG_SETFLAG(cfg_flags, SMF_CFG_SNAPLEN_SET);
 			break;
+#ifndef	_SOLARIS_
+		/*
+		 * This option requires a special securing on Solaris as
+		 * pflogd will be started manually in the case it is used.
+		 * Also, some polishing is needed so that the response
+		 * from 'pflogd -x' is shown to the user and not put into
+		 * a logfile.
+		 */
 		case 'x':
 			Xflag++;
 			break;
+#endif /* !_SOLARIS_ */
+#ifdef	_SOLARIS_
+		case 'C': 
+			create = 1;	/* FALLTHRU */
+		case 'c':
+			smf_instance = optarg;
+			break;
+#endif	/* _SOLARIS_ */
 		default:
 			usage();
 		}
@@ -732,14 +772,14 @@
 	argv += optind;
 
 	/* does interface exist */
-	if (!if_exists(interface)) {
+	if (SKIP_CHK(smf_instance) && !if_exists(interface)) {
 		warn("Failed to initialize: %s", interface);
 		logmsg(LOG_ERR, "Failed to initialize: %s", interface);
 		logmsg(LOG_ERR, "Exiting, init failure");
 		exit(1);
 	}
 
-	if (!Debug) {
+	if (SKIP_CHK(smf_instance) && !Debug) {
 		openlog("pflogd", LOG_PID | LOG_CONS, LOG_DAEMON);
 		if (daemon(0, 0)) {
 			logmsg(LOG_WARNING, "Failed to become daemon: %s",
@@ -757,6 +797,31 @@
 			logmsg(LOG_NOTICE, "Failed to form filter expression");
 	}
 
+#ifdef	_SOLARIS_
+	if (smf_instance != NULL) {
+		if (filter != NULL) {
+			CFG_SETFLAG(cfg_flags, SMF_CFG_EXPRESSION_SET);
+		} else {
+			filter = "";
+		}
+		if ((cfg_flags == 0) && (create == 0)) {
+			if (smf_print_pflogcfg(smf_instance)) {
+				exit (-1);
+			}
+		} else {
+			smf_pflogd_cfg.cfg_set = cfg_flags;
+			smf_pflogd_cfg.cfg_expression = strdup(filter);
+			smf_pflogd_cfg.cfg_interface = strdup(interface);
+			smf_pflogd_cfg.cfg_logfile = strdup(filename);
+			smf_pflogd_cfg.cfg_delay = delay;
+			smf_pflogd_cfg.cfg_snaplen = snaplen;
+
+			smf_write_pflogcfg(smf_instance, create);
+		}
+		exit(0);
+	}
+#endif	/* _SOLARIS_ */
+
 	/* initialize pcap before dropping privileges */
 	if (init_pcap()) {
 		logmsg(LOG_ERR, "Exiting, init failure");
@@ -768,7 +833,6 @@
 		logmsg(LOG_ERR, "unable to privsep");
 		exit(1);
 	}
-
 	setproctitle("[initializing]");
 	/* Process is now unprivileged and inside a chroot */
 #ifdef	_SOLARIS_
diff -Naur pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/pflogd.h pflogd-OPENBSD_5_5-OPENBSD_5_5/pflogd.h
--- pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/pflogd.h	2016-02-18 12:08:42.414919276 -0800
+++ pflogd-OPENBSD_5_5-OPENBSD_5_5/pflogd.h	2016-02-18 12:09:18.796727948 -0800
@@ -18,6 +18,8 @@
 
 #ifdef	_SOLARIS_
 #include <limits.h>
+#include <sys/types.h>
+#include <priv.h>
 #else /* !_SOLARIS_ */
 #include <sys/limits.h>
 #endif	/* _SOLARIS_ */
@@ -55,3 +57,27 @@
 int  receive_fd(int);
 
 extern int Debug;
+
+#ifdef _SOLARIS_
+#define DROP_PRIV(priv)                                         \
+	do {                                                    \
+		if (priv_set(PRIV_OFF, PRIV_PERMITTED, (priv),  \
+		    NULL) != 0) {                               \
+			fprintf(stderr,                         \
+			    "Unable to drop privileges.\n");    \
+			exit (-1);                              \
+		}                                               \
+	} while (0)
+
+#define DROP_PFLAG(flag)				\
+	do {						\
+		if (setpflags((flag), 0) != 0) {	\
+			fprintf(stderr,			\
+			    "Unable to drop pflag.\n");	\
+			exit (-1);			\
+		}					\
+} while (0)
+#else /* !_SOLARIS_ */
+#define DROP_PRIV(priv)
+#define DROP_PFLAG(flag)
+#endif /* _SOLARIS_ */
diff -Naur pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/privsep.c pflogd-OPENBSD_5_5-OPENBSD_5_5/privsep.c
--- pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/privsep.c	2016-02-18 12:07:34.219667793 -0800
+++ pflogd-OPENBSD_5_5-OPENBSD_5_5/privsep.c	2016-02-18 11:55:14.949135348 -0800
@@ -112,6 +112,7 @@
 #endif	/* !_SOLARIS_ */
 
 	child_pid = fork();
+	DROP_PRIV(PRIV_PROC_FORK);
 	if (child_pid < 0)
 		err(1, "fork() failed");
 
@@ -133,6 +134,7 @@
 		if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
 			err(1, "setresuid() failed");
 #endif	/* !_SOLARIS_ */
+		DROP_PFLAG(PRIV_XPOLICY);
 
 		close(socks[0]);
 		priv_fd = socks[1];
diff -Naur pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/smf-config.c pflogd-OPENBSD_5_5-OPENBSD_5_5/smf-config.c
--- pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/smf-config.c	1969-12-31 16:00:00.000000000 -0800
+++ pflogd-OPENBSD_5_5-OPENBSD_5_5/smf-config.c	2016-02-24 08:24:57.408744180 -0800
@@ -0,0 +1,713 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ */
+
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <err.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <libscf.h>
+#include <stddef.h>
+#include <libscf_priv.h>
+
+#include "pflogd.h"
+#include "smf-config.h"
+
+#define	PFLOGD_PG	"pflog"
+#define PFLOGD_PROP_VALUE_AUTH	"value_authorization"
+#define PFLOGD_PROP_ACTION_AUTH	"action_authorization"
+#define PFLOGD_VALUE_AUTH	"solaris.smf.value.network.firewall"
+#define PFLOGD_MANAGE_AUTH	"solaris.smf.manage.network.firewall"
+
+#define	SKIP_PROP(_pv_)		\
+	((strcmp((_pv_)->pv_prop, "action_authorization") == 0) || \
+	(strcmp((_pv_)->pv_prop, "value_authorization") == 0))
+
+#define	STRIP_SVC(_x_)	((_x_) + (sizeof ("svc:/") - 1))
+
+/*
+ * smf_pflogd_cfg
+ * FTP proxy configuration container.
+ */
+smf_pflogd_cfg_t	smf_pflogd_cfg;
+
+#define	SMF_OPT_OPTIONAL	0
+#define	SMF_OPT_MANDATORY	1
+/*
+ * X-macro table.
+ * Columns are as follows:
+ * 	value key/index 
+ *	SMF property name name
+ *	member in smf_pflogd_cfg_t structure
+ *	function which converts ASCIIZ to member type in smf_pflogd_cfg_t
+ *	function which converts member in smf_pflogd_cfg_t to ASCIIZ
+ *	optional/mandatory status
+ *      property type
+ */
+#define	X_CFG_PROPS	\
+	X(SMF_LOGFILE, "logfile", cfg_logfile, nop_in, nop_out,		\
+	    SMF_OPT_MANDATORY, SCF_TYPE_ASTRING)			\
+	X(SMF_SNAPLEN, "snaplen", cfg_snaplen, int_in, int_out,		\
+	    SMF_OPT_MANDATORY, SCF_TYPE_INTEGER)			\
+	X(SMF_INTERFACE, "interface", cfg_interface, nop_in, nop_out,	\
+	    SMF_OPT_MANDATORY, SCF_TYPE_ASTRING)			\
+	X(SMF_DELAY, "delay",	cfg_delay, int_in, int_out,		\
+	    SMF_OPT_OPTIONAL, SCF_TYPE_INTEGER)				\
+	X(SMF_EXPRESSION, "filter", cfg_expression, nop_in, nop_out,	\
+	    SMF_OPT_OPTIONAL, SCF_TYPE_ASTRING)
+
+static void nop_in(void *, void *);
+static void nop_out(void *, void *);
+static void int_in(void *, void *);
+static void int_out(void *, void *);
+
+/*
+ * smf_keys
+ * Keys (indexes) to `smf_propnames` dictionary.
+ */
+#define	X(_const_, _propname_, _decl_, _conv_in_, _conv_out_, _mandatory_, \
+    _type_) _const_,
+enum smf_keys {
+	X_CFG_PROPS
+	SMF_CFG_PROP_COUNT
+};
+#undef	X
+
+/*
+ * smf_propnames
+ * It's an array (dictionary), which translates property code (SMF_*) to
+ * property value name found `ftp-proxy` property group.
+ */
+#define	X(_const_, _propname_, _decl_, _conv_in_, _conv_out_, _mandatory_, \
+    _type_) _propname_,
+static const char *smf_propnames[] = {
+	X_CFG_PROPS
+	NULL
+};
+#undef	X
+
+/*
+ * smf_cfg_offsets
+ * Table of smf_pflogd_cfg_t members.
+ */
+#define	X(_const_, _propname_, _decl_, _conv_in_, _conv_out_, _mandatory_, \
+    _type_) offsetof(smf_pflogd_cfg_t, _decl_),
+static size_t smf_cfg_offsets[] = {
+	X_CFG_PROPS
+	sizeof (smf_pflogd_cfg_t)
+};
+#undef	X
+
+typedef void(*conv_in_f)(void *, void *);
+typedef void(*conv_out_f)(void *, void *);
+/*
+ * smf_convert_in
+ * Table of conversion functions, which convert particular smf_pflogd_cfg_t
+ * member into ASCIIZ.
+ */
+#define	X(_const_, _propname_, _decl_, _conv_in_, _conv_out_, _mandatory_, \
+    _type_) _conv_in_,
+static conv_in_f smf_conv_in[] = {
+	X_CFG_PROPS
+	NULL
+};
+#undef	X
+
+/*
+ * smf_conv_out
+ * Table of conversion functions, which convert ASCIIZ fetched from smf(5)
+ * repository to member of smf_pflogd_cfg_t structure.
+ */
+#define	X(_const_, _propname_, _decl_, _conv_in_, _conv_out_, _mandatory_, \
+    _type_) _conv_out_,
+static conv_out_f smf_conv_out[] = {
+	X_CFG_PROPS
+	NULL
+};
+#undef	X
+
+/*
+ * smf_mandatory
+ * Table marks configuration parameters, which must be defined by admin,
+ * before the service is enabled for the first time.
+ */
+#define	X(_const_, _propname_, _decl_, _conv_in_, _conv_out_, _mandatory_, \
+    _type_) _mandatory_,
+static int smf_mandatory[] = {
+	X_CFG_PROPS
+	0
+};
+#undef	X
+
+/*
+ * smf_type
+ * Table of types of SMF properties.
+ */
+#define	X(_const_, _propname_, _decl_, _conv_in_, _conv_out_, _mandatory_, \
+    _type_) _type_,
+static int smf_type[] = {
+	X_CFG_PROPS
+	0
+};
+#undef	X
+
+/*
+ * pflogd property group properties
+ * +1 for NULL termination.
+ * +1 for value_authorization
+ */
+static scf_propvec_t	prop_vec[SMF_CFG_PROP_COUNT + 1 + 1];
+
+/*
+ * general property group properties
+ * +1 for NULL termination.
+ * +2 for value_authorization/action_authorization
+ */
+static scf_propvec_t	gen_prop_vec[1 + 2];
+
+static int atexit_set = 0;
+static int complete_pflogdcfg(const char *);
+
+/*
+ * nop_in()
+ * Dummy conversion ASCIIZ to ASCIIZ, no allocation happens. Used when
+ * configuration is from smf(5).
+ */
+static void
+nop_in(void *asciiz, void *result)
+{
+	*((char **)result) = (char *)asciiz;
+}
+
+/*
+ * nop_out()
+ * Dummy conversion ASCIIZ to ASCIIZ, function allocates memory for result by
+ * strdup(3C). Used when configuration is written to smf(5) repository.
+ */
+static void
+nop_out(void *asciiz, void *val)
+{
+	*((char **)asciiz) = strdup(*(char **)val);
+}
+
+/*
+ * int_in()
+ * Dummy conversion of int64_t. No allocation happens. Used when reading
+ * values from smf.
+ */
+static void
+int_in(void *in, void *out) {
+	*((int64_t *)out) = *((int64_t *)in);
+}
+
+/*
+ * int_out()
+ * Dummy conversion of int64_t, storing into a newly allocated memory.
+ * Used when storing values to smf repository.
+ */
+static void
+int_out(void *out, void *in) {
+	int64_t **out_ = (int64_t **)out;
+
+	*out_ = malloc(sizeof (int64_t));
+	if (*out_ != NULL)
+		**out_ = *((int64_t *)in);
+}
+
+static void
+clear_prop_vec2(scf_propvec_t *prop_vec_ptr, int count)
+{
+	while (count--) {
+		prop_vec_ptr->pv_prop = NULL;
+		prop_vec_ptr->pv_desc = NULL;
+		prop_vec_ptr->pv_type = 0;
+		prop_vec_ptr->pv_aux = 0;
+		prop_vec_ptr->pv_mval = 0;
+
+		if (prop_vec_ptr->pv_ptr != NULL) {
+			free(prop_vec_ptr->pv_ptr);
+			prop_vec_ptr->pv_ptr = NULL;
+		}
+
+		prop_vec_ptr++;
+	}
+}
+
+/*
+ * clear_prop_vec()
+ * Function clears global variables `prop_vec` and `gen_prop_vec`,
+ * which are vectors of properties.
+ */
+static void
+clear_prop_vec()
+{
+	clear_prop_vec2(prop_vec,
+	    sizeof (prop_vec) / sizeof (scf_propvec_t));
+	clear_prop_vec2(gen_prop_vec,
+	    sizeof (gen_prop_vec) / sizeof (scf_propvec_t));
+}
+
+/*
+ * cfg_to_prop_vec()
+ * Function converts smf_pflogd_cfg global variable, which holds configuration
+ * parsed from command line arguments, to prop_vec, which is a smf(5) friendly
+ * representation of pflogd configuration. 
+ *
+ * Additionally, it populates gen_prop_vec to specify needed authorizations.
+ *
+ * Returns 0 on success, -1 on out of memory error.
+ */
+static int
+cfg_to_prop_vec(void)
+{
+	int		cfg_bit = 1;
+	int		i;
+	scf_propvec_t	*prop_vec_ptr = prop_vec;
+	conv_out_f	conv_func;
+
+	clear_prop_vec();
+
+	for (i = 0; i < SMF_CFG_PROP_COUNT; i++) {
+		if ((smf_pflogd_cfg.cfg_set & cfg_bit) != 0) {
+			prop_vec_ptr->pv_prop = smf_propnames[i];
+			conv_func = smf_conv_out[i];
+
+			conv_func(&prop_vec_ptr->pv_ptr,
+			    ((char *)&smf_pflogd_cfg + smf_cfg_offsets[i]));
+			if (prop_vec_ptr->pv_ptr == NULL)
+				return (-1);
+			prop_vec_ptr->pv_type = smf_type[i];
+			prop_vec_ptr++;
+		}
+		cfg_bit = cfg_bit << 1;
+	}
+	prop_vec_ptr->pv_type = SCF_TYPE_ASTRING;
+	prop_vec_ptr->pv_prop = PFLOGD_PROP_VALUE_AUTH;
+	prop_vec_ptr->pv_ptr = strdup(PFLOGD_VALUE_AUTH);
+	prop_vec_ptr++;
+
+	gen_prop_vec[0].pv_type = SCF_TYPE_ASTRING;
+	gen_prop_vec[0].pv_prop = PFLOGD_PROP_VALUE_AUTH;
+	gen_prop_vec[0].pv_ptr = strdup(PFLOGD_MANAGE_AUTH);
+	gen_prop_vec[1].pv_type = SCF_TYPE_ASTRING;
+	gen_prop_vec[1].pv_prop = PFLOGD_PROP_ACTION_AUTH;
+	gen_prop_vec[1].pv_ptr = strdup(PFLOGD_MANAGE_AUTH);
+
+	return (0);
+}
+
+/*
+ * prop_vec_to_cfg()
+ * Converts global variable `prop_vec` to `smf_pflogd_cfg` global variable,
+ * which is understood by main().
+ */
+static void
+prop_vec_to_cfg(void)
+{
+	int		i;
+	scf_propvec_t	*prop_vec_ptr = prop_vec;
+	conv_in_f	conv_func;
+
+	for (i = 0; i < SMF_CFG_PROP_COUNT; i++, prop_vec_ptr++) {
+		if (SKIP_PROP(prop_vec_ptr)) {
+			/*
+			 * We have `hidden` properties: action/value smf
+			 * authorization. Those two are not kept in
+			 * smf_ftp_cfg.
+			 *
+			 * So we must to skip to next property in vector
+			 * without letting for loop to advance its counter, so
+			 * we compensate here by doing `i--`.
+			 */
+			i--;
+			continue;
+		};
+		conv_func = smf_conv_in[i];
+		conv_func(prop_vec_ptr->pv_ptr,
+		    ((char *)&smf_pflogd_cfg + smf_cfg_offsets[i]));
+	}
+}
+
+/*
+ * smf_print_pflogcfg()
+ * Function loads pflogdcfg from smf(5) repository and prints configuration to
+ * standard output. We use `scf_simple_prop_get(3SCF)`.
+ *
+ * Returns 0 on success, -1 on error.
+ */
+int
+smf_print_pflogcfg(const char *smf_instance)
+{
+	scf_simple_prop_t	*prop;
+	char			*propval;
+	int			i;
+	scf_propvec_t		*prop_vec_ptr = prop_vec;
+	int			cfg_undefined = 0;
+	char			*fmri;
+
+	if (atexit_set == 0) {
+		atexit(clear_prop_vec);
+		bzero(&smf_pflogd_cfg, sizeof (smf_pflogd_cfg_t));
+		atexit_set = 1;
+	}
+
+	(void) asprintf(&fmri, "%s:%s", BASE_FMRI, smf_instance);
+	if (fmri == NULL) {
+		fprintf(stderr, "Out of memory.\n");
+		return (-1);
+	}
+
+	clear_prop_vec();
+
+	for (i = 0; i < SMF_CFG_PROP_COUNT; i++) {
+		prop = scf_simple_prop_get(NULL, fmri, PFLOGD_PG,
+		    smf_propnames[i]);
+		prop_vec_ptr->pv_prop = smf_propnames[i];
+
+		if (prop == NULL) {
+			/*
+			 * Property not defined, so we create a kind of
+			 * 'placeholder' with empty value.
+			 *
+			 * calloc() works well for both astring and integer.
+			 */
+			prop_vec_ptr->pv_type = smf_type[i];
+			prop_vec_ptr->pv_ptr = calloc(1, sizeof (int64_t));
+			cfg_undefined |= smf_mandatory[i];
+		} else {
+			prop_vec_ptr->pv_type = scf_simple_prop_type(prop);
+			if (prop_vec_ptr->pv_type == -1) {
+				free(fmri);
+				fprintf(stderr,
+				    "Failed to get property type.\n");
+				return (-1);
+			}
+			if (prop_vec_ptr->pv_type != smf_type[i]) {
+				free(fmri);
+				fprintf(stderr,
+				    "Property %s has unexpected type.\n",
+				    smf_propnames[i]);
+				return (-1);
+			}
+
+			if (smf_type[i] == SCF_TYPE_ASTRING) {
+				char	*propval;
+				propval = scf_simple_prop_next_astring(prop);
+				if (propval == NULL) {
+					propval = "";
+				}
+				prop_vec_ptr->pv_ptr = strdup(propval);
+
+				if (propval[0] == 0) {
+					cfg_undefined |= smf_mandatory[i];
+				}
+			} else {
+				/* smf_type[i] == SCF_TYPE_INTEGER */
+				int64_t	*propval;
+				int64_t propval_;
+
+				propval = scf_simple_prop_next_integer(prop);
+				propval_ = (propval == NULL) ? (0) : (*propval);
+
+				prop_vec_ptr->pv_ptr = malloc(sizeof (int64_t));
+				if (prop_vec_ptr->pv_ptr != NULL) {
+					*((int64_t *)prop_vec_ptr->pv_ptr) =
+					    propval_;
+				}
+				if (propval_ == 0) {
+					cfg_undefined |= smf_mandatory[i];
+				}
+			}
+			scf_simple_prop_free(prop);
+		}
+		if (prop_vec_ptr->pv_ptr == NULL) {
+			free(fmri);
+			fprintf(stderr, "Out of memory.\n");
+			return (-1);
+		}
+
+		prop_vec_ptr++;
+	}
+
+	printf("PF pflogd configuration:\n");
+
+	prop_vec_ptr = prop_vec;
+	for (i = 0; i < SMF_CFG_PROP_COUNT; i++) {
+		if (smf_type[i] == SCF_TYPE_ASTRING) {
+			const char *val = (const char *)prop_vec_ptr->pv_ptr;
+			printf("\t- %s:\n\t\t%s\n", prop_vec_ptr->pv_prop,
+			    ((val[0] == '\0') ?  "?? undefined ??" : val));
+		} else {
+			/* smf_type[i] == SCF_TYPE_INTEGER */
+			int64_t val = *((int64_t *)prop_vec_ptr->pv_ptr);
+			if (val == 0) {
+				printf("\t- %s:\n\t\t%s\n", prop_vec_ptr->pv_prop,
+			    	    "?? undefined ??");
+			} else {
+				printf("\t- %s:\n\t\t%d\n", prop_vec_ptr->pv_prop,
+			    	    (int)val);
+			}
+		}
+		prop_vec_ptr++;
+	}
+	if (cfg_undefined) {
+		printf("\n\nConfiguration for %s is incomplete."
+		    " Service will not run.\n\n", fmri);
+	} else {
+		prop_vec_to_cfg();
+		printf(
+		    "\n\n%s service is being launched using cmd line below\n",
+		    fmri);
+		printf("pflogd -d %d -i %s -s %d -f %s %s\n\n",
+		    (int)smf_pflogd_cfg.cfg_delay, smf_pflogd_cfg.cfg_interface,
+		    (int)smf_pflogd_cfg.cfg_snaplen, smf_pflogd_cfg.cfg_logfile,
+		    smf_pflogd_cfg.cfg_expression);
+	}
+
+	free(fmri);
+
+	return (0);
+}
+
+/*
+ * smf_create_pflogd_instance()
+ * Function creates a new instance in smf(5) repository.
+ */
+static int
+smf_create_pflogd_instance(const char *smf_instance)
+{
+	scf_handle_t	*h_scf = NULL;
+	scf_scope_t	*scp_scf = NULL;
+	scf_service_t	*svc_scf = NULL;
+	scf_instance_t	*sin_scf = NULL;
+	int	rv = -1;
+
+ 	h_scf = scf_handle_create(SCF_VERSION);
+	if ((h_scf == NULL) || (scf_handle_bind(h_scf) == -1)) {
+		(void) fprintf(stderr, "scf_handle_bind() failed - %s\n",
+		    scf_strerror(scf_error()));
+		if (h_scf != NULL) {
+			scf_handle_destroy(h_scf);
+		}
+		return (-1);
+	}
+
+	if ((scp_scf = scf_scope_create(h_scf)) == NULL) {
+		(void) fprintf(stderr, "could not create scope - %s\n",
+		    scf_strerror(scf_error()));
+		goto unbind;
+	}
+
+	if (scf_handle_get_local_scope(h_scf, scp_scf) != 0) {
+		(void) fprintf(stderr, "could not get scope - %s\n",
+		    scf_strerror(scf_error()));
+		goto scope_destroy;
+	}
+
+	if ((svc_scf = scf_service_create(h_scf)) == NULL) {
+		(void) fprintf(stderr, "could not create service - %s\n",
+		    scf_strerror(scf_error()));
+		goto scope_destroy;
+	}
+
+	if ((sin_scf = scf_instance_create(h_scf)) == NULL) {
+		(void) fprintf(stderr, "could not get instance handle - %s\n",
+		    scf_strerror(scf_error()));
+		goto service_destroy;
+	}
+
+	if (scf_scope_get_service(scp_scf, STRIP_SVC(BASE_FMRI), svc_scf) !=
+	    SCF_SUCCESS) {
+		(void) fprintf(stderr, "could not select service (%s)\n",
+		    scf_strerror(scf_error()));
+		goto instance_destroy;
+	}
+
+	if (scf_service_add_instance(svc_scf, smf_instance, sin_scf) != 0) {
+		(void) fprintf(stderr, "could not add %s instance - %s\n",
+		    smf_instance, scf_strerror(scf_error()));
+		goto instance_destroy;
+	}
+
+	if (scf_instance_add_pg(sin_scf, "general", "framework", 0,
+	    NULL) != SCF_SUCCESS) {
+		(void) fprintf(stderr,
+		    "could not create property group - %s\n",
+		    scf_strerror(scf_error()));
+		goto instance_delete;
+	}
+
+	if (scf_instance_add_pg(sin_scf, PFLOGD_PG, "application", 0,
+	    NULL) != SCF_SUCCESS) {
+		(void) fprintf(stderr,
+		    "could not create property group - %s\n",
+		    scf_strerror(scf_error()));
+		goto instance_delete;
+	}
+
+	rv = 0;
+	goto instance_destroy;
+
+instance_delete:
+	if (scf_instance_delete(sin_scf) != 0) {
+		fprintf(stderr, "Can't delete the newly created instance:");
+		fprintf(stderr, "\t%s\n", scf_strerror(scf_error()));
+	}
+instance_destroy:
+	scf_instance_destroy(sin_scf);
+service_destroy:
+	scf_service_destroy(svc_scf);
+scope_destroy:
+	scf_scope_destroy(scp_scf);
+unbind:
+	scf_handle_unbind(h_scf);
+	scf_handle_destroy(h_scf);
+
+	return (rv);
+}
+
+/*
+ * smf_write_pflogcfg()
+ * Function writes pflogd configuration to smf(5) repository.
+ */
+int
+smf_write_pflogcfg(const char *smf_instance, int create)
+{
+	int	i;
+	scf_propvec_t
+		*bad_prop_vec = NULL;
+	char	*fmri;
+
+	if (atexit_set == 0) {
+		atexit(clear_prop_vec);
+		bzero(prop_vec, sizeof (prop_vec));
+		atexit_set = 1;
+	}
+
+	if (create && (complete_pflogdcfg(smf_instance) != 0)) {
+		fprintf(stderr, "Out of memory.\n");
+		return (-1);
+	}
+
+	if (cfg_to_prop_vec() != 0) {
+		fprintf(stderr, "Out of memory.\n");
+		return (-1);
+	}
+
+	(void) asprintf(&fmri, "%s:%s", BASE_FMRI, smf_instance);
+	if (fmri == NULL) {
+		fprintf(stderr, "Out of memory.\n");
+		return (-1);
+	}
+
+	if (create) {
+		if (smf_create_pflogd_instance(smf_instance) != 0) {
+			free(fmri);
+			return (-1);
+		}
+	}
+
+	if (create && (scf_write_propvec(fmri, "general", gen_prop_vec,
+	    &bad_prop_vec) != SCF_SUCCESS)) {
+		fprintf(stderr, "Can't update %s configuration:", fmri);
+		fprintf(stderr, "\t%s\n", scf_strerror(scf_error()));
+		if (bad_prop_vec != NULL) {
+			fprintf(stderr, "Could not set %s\n",
+			    bad_prop_vec->pv_prop);
+		}
+		free(fmri);
+		exit(1);
+	}
+
+	bad_prop_vec = NULL;
+	if (scf_write_propvec(fmri, PFLOGD_PG, prop_vec, &bad_prop_vec)
+	    != SCF_SUCCESS) {
+		fprintf(stderr, "Can't update %s configuration:", fmri);
+		fprintf(stderr, "\t%s\n", scf_strerror(scf_error()));
+		if (bad_prop_vec != NULL) {
+			fprintf(stderr, "Could not set %s\n",
+			    bad_prop_vec->pv_prop);
+		}
+		free(fmri);
+		exit(1);
+	}
+
+	free(fmri);
+	return (0);
+}
+
+/*
+ * complete_pflogdcfg()
+ * Function sets default values to properties, which are unset/undefined when
+ * new smf(5) instance is being created.
+ *
+ * Returns 0 on success, -1 on out of memory error.
+ */
+static int
+complete_pflogdcfg(const char *smf_instance)
+{
+	int	i;
+	int	f = 1;
+
+	for (i = 0; i < SMF_CFG_PROP_COUNT; i++) {
+		if ((smf_pflogd_cfg.cfg_set & f) == 0) {
+			switch (i) {
+			case SMF_LOGFILE:
+				(void) asprintf(&smf_pflogd_cfg.cfg_logfile,
+				    "%s/%s", PFLOGD_LOG_DIR, smf_instance);
+				if (smf_pflogd_cfg.cfg_logfile == NULL) {
+					return (-1);
+				}
+				smf_pflogd_cfg.cfg_set |= SMF_CFG_LOGFILE_SET;	
+				break;
+			case SMF_INTERFACE:
+				smf_pflogd_cfg.cfg_interface = strdup(smf_instance);
+				if (smf_pflogd_cfg.cfg_interface == NULL) {
+					return (-1);
+				}
+				smf_pflogd_cfg.cfg_set |= SMF_CFG_INTERFACE_SET;
+				break;
+			case SMF_SNAPLEN:
+				smf_pflogd_cfg.cfg_snaplen = DEF_SNAPLEN;
+				smf_pflogd_cfg.cfg_set |= SMF_CFG_SNAPLEN_SET;
+				break;
+			case SMF_DELAY:
+				smf_pflogd_cfg.cfg_delay = FLUSH_DELAY;
+				smf_pflogd_cfg.cfg_set |= SMF_CFG_DELAY_SET;
+				break;
+			case SMF_EXPRESSION:
+				smf_pflogd_cfg.cfg_expression = strdup("");
+				smf_pflogd_cfg.cfg_set |= SMF_CFG_EXPRESSION_SET;
+				break;
+			default: ;
+			}
+		}
+		f = f << 1;
+	}
+
+	return (0);
+}
diff -Naur pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/smf-config.h pflogd-OPENBSD_5_5-OPENBSD_5_5/smf-config.h
--- pflogd-OPENBSD_5_5-OPENBSD_5_5.pre-smf/smf-config.h	1969-12-31 16:00:00.000000000 -0800
+++ pflogd-OPENBSD_5_5-OPENBSD_5_5/smf-config.h	2016-02-17 01:17:14.520118386 -0800
@@ -0,0 +1,53 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ */
+
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef	_SMF_CONFIG_H_
+#define	_SMF_CONFIG_H_
+
+#define	BASE_FMRI		"svc:/network/firewall/pflog"
+#define	DEFAULT_INSTANCE	"pflog0"
+
+#define	SMF_CFG_LOGFILE_SET	0x00000001
+#define	SMF_CFG_SNAPLEN_SET	0x00000002
+#define	SMF_CFG_INTERFACE_SET	0x00000004
+#define	SMF_CFG_DELAY_SET	0x00000008
+#define	SMF_CFG_EXPRESSION_SET	0x00000010
+
+typedef struct smf_pflogd_cfg {
+	unsigned int	cfg_set;	/* SMF_CFG_*_SET bit field */
+	char		*cfg_logfile;
+	int64_t		cfg_snaplen;
+	char 		*cfg_interface;
+	int64_t		cfg_delay;
+	char		*cfg_expression;
+} smf_pflogd_cfg_t;
+
+extern smf_pflogd_cfg_t	smf_pflogd_cfg;
+
+extern int smf_print_pflogcfg(const char *);
+extern int smf_write_pflogcfg(const char *, int);
+
+#endif	/* !_SMF_CONFIG_H_ */