xref: /onnv-gate/usr/src/cmd/ipf/svc/ipfd.c (revision 8823:000507e9108d)
1*8823STruong.Q.Nguyen@Sun.COM /*
2*8823STruong.Q.Nguyen@Sun.COM  * CDDL HEADER START
3*8823STruong.Q.Nguyen@Sun.COM  *
4*8823STruong.Q.Nguyen@Sun.COM  * The contents of this file are subject to the terms of the
5*8823STruong.Q.Nguyen@Sun.COM  * Common Development and Distribution License (the "License").
6*8823STruong.Q.Nguyen@Sun.COM  * You may not use this file except in compliance with the License.
7*8823STruong.Q.Nguyen@Sun.COM  *
8*8823STruong.Q.Nguyen@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*8823STruong.Q.Nguyen@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*8823STruong.Q.Nguyen@Sun.COM  * See the License for the specific language governing permissions
11*8823STruong.Q.Nguyen@Sun.COM  * and limitations under the License.
12*8823STruong.Q.Nguyen@Sun.COM  *
13*8823STruong.Q.Nguyen@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*8823STruong.Q.Nguyen@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*8823STruong.Q.Nguyen@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*8823STruong.Q.Nguyen@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*8823STruong.Q.Nguyen@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*8823STruong.Q.Nguyen@Sun.COM  *
19*8823STruong.Q.Nguyen@Sun.COM  * CDDL HEADER END
20*8823STruong.Q.Nguyen@Sun.COM  */
21*8823STruong.Q.Nguyen@Sun.COM 
22*8823STruong.Q.Nguyen@Sun.COM /*
23*8823STruong.Q.Nguyen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*8823STruong.Q.Nguyen@Sun.COM  * Use is subject to license terms.
25*8823STruong.Q.Nguyen@Sun.COM  */
26*8823STruong.Q.Nguyen@Sun.COM 
27*8823STruong.Q.Nguyen@Sun.COM /*
28*8823STruong.Q.Nguyen@Sun.COM  * This file delivers svc.ipfd, the daemon that monitors changes to
29*8823STruong.Q.Nguyen@Sun.COM  * firewall capable services and requests IPfilter configuration update
30*8823STruong.Q.Nguyen@Sun.COM  * on behalf of the service. Essentially, the daemon listens for
31*8823STruong.Q.Nguyen@Sun.COM  * service changes and forks the program that update a service's
32*8823STruong.Q.Nguyen@Sun.COM  * IPfilter configuration.
33*8823STruong.Q.Nguyen@Sun.COM  *
34*8823STruong.Q.Nguyen@Sun.COM  * - A firewall capable SMF service can restrict network access to its
35*8823STruong.Q.Nguyen@Sun.COM  *   service by providing a firewall policy that can be translated into
36*8823STruong.Q.Nguyen@Sun.COM  *   a set of IPfilter rules. The mentioned firewall policy is stored in
37*8823STruong.Q.Nguyen@Sun.COM  *   firewall_config and firewall_context property groups. If one of these
38*8823STruong.Q.Nguyen@Sun.COM  *   two property groups exist, the service is considered to be firewall
39*8823STruong.Q.Nguyen@Sun.COM  *   capable.
40*8823STruong.Q.Nguyen@Sun.COM  *
41*8823STruong.Q.Nguyen@Sun.COM  * - A request to update service's IPfilter configuration is made for
42*8823STruong.Q.Nguyen@Sun.COM  *   actions that affect service's configuration or running state. The
43*8823STruong.Q.Nguyen@Sun.COM  *   actions are:
44*8823STruong.Q.Nguyen@Sun.COM  *	- enable/disable
45*8823STruong.Q.Nguyen@Sun.COM  *	- refresh/restart
46*8823STruong.Q.Nguyen@Sun.COM  *	- maintenance/clear maintenance
47*8823STruong.Q.Nguyen@Sun.COM  *
48*8823STruong.Q.Nguyen@Sun.COM  * Lacking a generic SMF mechanism to observe service state changes, the
49*8823STruong.Q.Nguyen@Sun.COM  * daemon observe change events by listening to changes to 'general',
50*8823STruong.Q.Nguyen@Sun.COM  * 'general_ovr', and 'restarter_actions' property groups. This is not a
51*8823STruong.Q.Nguyen@Sun.COM  * stable interface and should be replaced when a SMF supported mechanism
52*8823STruong.Q.Nguyen@Sun.COM  * becomes available.
53*8823STruong.Q.Nguyen@Sun.COM  *
54*8823STruong.Q.Nguyen@Sun.COM  * - The program responsible for updating service's IPfilter configuration
55*8823STruong.Q.Nguyen@Sun.COM  *   is /lib/svc/method/ipfilter. This program is called as:
56*8823STruong.Q.Nguyen@Sun.COM  *
57*8823STruong.Q.Nguyen@Sun.COM  *   /lib/svc/method/ipfilter fw_update fmri
58*8823STruong.Q.Nguyen@Sun.COM  *
59*8823STruong.Q.Nguyen@Sun.COM  *   where fmri the instance fmri of the service to be updated.
60*8823STruong.Q.Nguyen@Sun.COM  */
61*8823STruong.Q.Nguyen@Sun.COM 
62*8823STruong.Q.Nguyen@Sun.COM #include <stdio.h>
63*8823STruong.Q.Nguyen@Sun.COM #include <unistd.h>
64*8823STruong.Q.Nguyen@Sun.COM #include <stdlib.h>
65*8823STruong.Q.Nguyen@Sun.COM #include <assert.h>
66*8823STruong.Q.Nguyen@Sun.COM #include <errno.h>
67*8823STruong.Q.Nguyen@Sun.COM #include <sys/types.h>
68*8823STruong.Q.Nguyen@Sun.COM #include <sys/stat.h>
69*8823STruong.Q.Nguyen@Sun.COM #include <sys/wait.h>
70*8823STruong.Q.Nguyen@Sun.COM #include <fcntl.h>
71*8823STruong.Q.Nguyen@Sun.COM #include <umem.h>
72*8823STruong.Q.Nguyen@Sun.COM #include <libscf.h>
73*8823STruong.Q.Nguyen@Sun.COM #include <libscf_priv.h>
74*8823STruong.Q.Nguyen@Sun.COM #include <signal.h>
75*8823STruong.Q.Nguyen@Sun.COM #include <string.h>
76*8823STruong.Q.Nguyen@Sun.COM #include <syslog.h>
77*8823STruong.Q.Nguyen@Sun.COM 
78*8823STruong.Q.Nguyen@Sun.COM #define	IPFILTER_FMRI		"svc:/network/ipfilter:default"
79*8823STruong.Q.Nguyen@Sun.COM #define	RPCBIND_FMRI		"svc:/network/rpc/bind:default"
80*8823STruong.Q.Nguyen@Sun.COM #define	IPF_UPDATE_CMD		"/lib/svc/method/ipfilter"
81*8823STruong.Q.Nguyen@Sun.COM 
82*8823STruong.Q.Nguyen@Sun.COM #define	SCF_SNAPSHOT_RUNNING	"running"
83*8823STruong.Q.Nguyen@Sun.COM #define	SCF_PG_FW_CONTEXT	"firewall_context"
84*8823STruong.Q.Nguyen@Sun.COM #define	SCF_PG_FW_CONFIG	"firewall_config"
85*8823STruong.Q.Nguyen@Sun.COM #define	SCF_PG_REFRESH		"refresh"
86*8823STruong.Q.Nguyen@Sun.COM #define	SCF_PG_INETD		"inetd"
87*8823STruong.Q.Nguyen@Sun.COM 
88*8823STruong.Q.Nguyen@Sun.COM #define	SCF_PROPERTY_ISRPC	"isrpc"
89*8823STruong.Q.Nguyen@Sun.COM 
90*8823STruong.Q.Nguyen@Sun.COM #define	MAX_RETRY		7
91*8823STruong.Q.Nguyen@Sun.COM #define	DEV_NULL		"/dev/null"
92*8823STruong.Q.Nguyen@Sun.COM 
93*8823STruong.Q.Nguyen@Sun.COM static scf_handle_t *h;
94*8823STruong.Q.Nguyen@Sun.COM static ssize_t max_scf_fmri_size;
95*8823STruong.Q.Nguyen@Sun.COM static ssize_t max_scf_name_size;
96*8823STruong.Q.Nguyen@Sun.COM 
97*8823STruong.Q.Nguyen@Sun.COM static scf_instance_t *inst;
98*8823STruong.Q.Nguyen@Sun.COM static scf_snapshot_t *snap;
99*8823STruong.Q.Nguyen@Sun.COM static scf_propertygroup_t *scratch_pg;
100*8823STruong.Q.Nguyen@Sun.COM static scf_property_t *scratch_prop;
101*8823STruong.Q.Nguyen@Sun.COM static scf_value_t *scratch_v;
102*8823STruong.Q.Nguyen@Sun.COM 
103*8823STruong.Q.Nguyen@Sun.COM static char *scratch_fmri;
104*8823STruong.Q.Nguyen@Sun.COM static char *scratch_name;
105*8823STruong.Q.Nguyen@Sun.COM 
106*8823STruong.Q.Nguyen@Sun.COM static const char *all_props[] = {
107*8823STruong.Q.Nguyen@Sun.COM 	SCF_PROPERTY_REFRESH, SCF_PROPERTY_RESTART, SCF_PROPERTY_MAINT_ON,
108*8823STruong.Q.Nguyen@Sun.COM 	SCF_PROPERTY_MAINT_ON_IMMEDIATE, SCF_PROPERTY_MAINT_ON_IMMTEMP,
109*8823STruong.Q.Nguyen@Sun.COM 	SCF_PROPERTY_MAINT_ON_TEMPORARY, SCF_PROPERTY_MAINT_OFF
110*8823STruong.Q.Nguyen@Sun.COM };
111*8823STruong.Q.Nguyen@Sun.COM #define	ALL_PROPS_CNT		7
112*8823STruong.Q.Nguyen@Sun.COM 
113*8823STruong.Q.Nguyen@Sun.COM static const char *maint_props[] = {
114*8823STruong.Q.Nguyen@Sun.COM 	SCF_PROPERTY_REFRESH, SCF_PROPERTY_RESTART, SCF_PROPERTY_MAINT_OFF };
115*8823STruong.Q.Nguyen@Sun.COM #define	MAINT_PROPS_CNT		3
116*8823STruong.Q.Nguyen@Sun.COM 
117*8823STruong.Q.Nguyen@Sun.COM static int ipfilter_update(const char *);
118*8823STruong.Q.Nguyen@Sun.COM 
119*8823STruong.Q.Nguyen@Sun.COM static int
daemonize_self(void)120*8823STruong.Q.Nguyen@Sun.COM daemonize_self(void)
121*8823STruong.Q.Nguyen@Sun.COM {
122*8823STruong.Q.Nguyen@Sun.COM 	pid_t pid;
123*8823STruong.Q.Nguyen@Sun.COM 	int fd;
124*8823STruong.Q.Nguyen@Sun.COM 
125*8823STruong.Q.Nguyen@Sun.COM 	(void) close(STDIN_FILENO);
126*8823STruong.Q.Nguyen@Sun.COM 
127*8823STruong.Q.Nguyen@Sun.COM 	if ((fd = open(DEV_NULL, O_RDONLY)) == -1) {
128*8823STruong.Q.Nguyen@Sun.COM 		(void) printf("Could not open /dev/null: %s\n",
129*8823STruong.Q.Nguyen@Sun.COM 		    strerror(errno));
130*8823STruong.Q.Nguyen@Sun.COM 	} else if (fd != STDIN_FILENO) {
131*8823STruong.Q.Nguyen@Sun.COM 		(void) dup2(fd, STDIN_FILENO);
132*8823STruong.Q.Nguyen@Sun.COM 		(void) close(fd);
133*8823STruong.Q.Nguyen@Sun.COM 	}
134*8823STruong.Q.Nguyen@Sun.COM 	(void) dup2(STDERR_FILENO, STDOUT_FILENO);
135*8823STruong.Q.Nguyen@Sun.COM 	closefrom(3);
136*8823STruong.Q.Nguyen@Sun.COM 
137*8823STruong.Q.Nguyen@Sun.COM 	if ((pid = fork1()) < 0) {
138*8823STruong.Q.Nguyen@Sun.COM 		(void) printf("fork() failed: %s\n", strerror(errno));
139*8823STruong.Q.Nguyen@Sun.COM 		return (1);
140*8823STruong.Q.Nguyen@Sun.COM 	}
141*8823STruong.Q.Nguyen@Sun.COM 
142*8823STruong.Q.Nguyen@Sun.COM 	if (pid != 0)
143*8823STruong.Q.Nguyen@Sun.COM 		exit(0);
144*8823STruong.Q.Nguyen@Sun.COM 
145*8823STruong.Q.Nguyen@Sun.COM 	(void) setsid();
146*8823STruong.Q.Nguyen@Sun.COM 	(void) chdir("/");
147*8823STruong.Q.Nguyen@Sun.COM 
148*8823STruong.Q.Nguyen@Sun.COM 	return (0);
149*8823STruong.Q.Nguyen@Sun.COM }
150*8823STruong.Q.Nguyen@Sun.COM 
151*8823STruong.Q.Nguyen@Sun.COM static void
repository_rebind(scf_handle_t * hndl)152*8823STruong.Q.Nguyen@Sun.COM repository_rebind(scf_handle_t *hndl)
153*8823STruong.Q.Nguyen@Sun.COM {
154*8823STruong.Q.Nguyen@Sun.COM 	int c = 0;
155*8823STruong.Q.Nguyen@Sun.COM 
156*8823STruong.Q.Nguyen@Sun.COM 	(void) scf_handle_unbind(hndl);
157*8823STruong.Q.Nguyen@Sun.COM 	while ((scf_handle_bind(hndl)) != 0) {
158*8823STruong.Q.Nguyen@Sun.COM 		if (c > MAX_RETRY) {
159*8823STruong.Q.Nguyen@Sun.COM 			syslog(LOG_ERR | LOG_DAEMON, "Repository access "
160*8823STruong.Q.Nguyen@Sun.COM 			    "unavailable. Couldn't bind handle: %s\n",
161*8823STruong.Q.Nguyen@Sun.COM 			    scf_strerror(scf_error()));
162*8823STruong.Q.Nguyen@Sun.COM 			syslog(LOG_ERR | LOG_DAEMON, "Service specific"
163*8823STruong.Q.Nguyen@Sun.COM 			    "IPfilter configuration may not be updated "
164*8823STruong.Q.Nguyen@Sun.COM 			    "properly\n");
165*8823STruong.Q.Nguyen@Sun.COM 
166*8823STruong.Q.Nguyen@Sun.COM 			exit(1);
167*8823STruong.Q.Nguyen@Sun.COM 		} else {
168*8823STruong.Q.Nguyen@Sun.COM 			c++;
169*8823STruong.Q.Nguyen@Sun.COM 		}
170*8823STruong.Q.Nguyen@Sun.COM 
171*8823STruong.Q.Nguyen@Sun.COM 		(void) sleep(1);
172*8823STruong.Q.Nguyen@Sun.COM 	}
173*8823STruong.Q.Nguyen@Sun.COM }
174*8823STruong.Q.Nguyen@Sun.COM 
175*8823STruong.Q.Nguyen@Sun.COM static void
repository_notify_setup(scf_handle_t * h)176*8823STruong.Q.Nguyen@Sun.COM repository_notify_setup(scf_handle_t *h)
177*8823STruong.Q.Nguyen@Sun.COM {
178*8823STruong.Q.Nguyen@Sun.COM 	for (;;) {
179*8823STruong.Q.Nguyen@Sun.COM 		if (_scf_notify_add_pgtype(h, SCF_GROUP_FRAMEWORK) ==
180*8823STruong.Q.Nguyen@Sun.COM 		    SCF_SUCCESS)
181*8823STruong.Q.Nguyen@Sun.COM 			break;
182*8823STruong.Q.Nguyen@Sun.COM 
183*8823STruong.Q.Nguyen@Sun.COM 		switch (scf_error()) {
184*8823STruong.Q.Nguyen@Sun.COM 		case SCF_ERROR_CONNECTION_BROKEN:
185*8823STruong.Q.Nguyen@Sun.COM 			repository_rebind(h);
186*8823STruong.Q.Nguyen@Sun.COM 			break;
187*8823STruong.Q.Nguyen@Sun.COM 
188*8823STruong.Q.Nguyen@Sun.COM 		case SCF_ERROR_NO_RESOURCES:
189*8823STruong.Q.Nguyen@Sun.COM 			(void) sleep(1);
190*8823STruong.Q.Nguyen@Sun.COM 			break;
191*8823STruong.Q.Nguyen@Sun.COM 
192*8823STruong.Q.Nguyen@Sun.COM 		default:
193*8823STruong.Q.Nguyen@Sun.COM 			syslog(LOG_ERR | LOG_DAEMON,
194*8823STruong.Q.Nguyen@Sun.COM 			    "Abort: Couldn't set up repository notification "
195*8823STruong.Q.Nguyen@Sun.COM 			    "for pg type %s: %s\n", SCF_GROUP_FRAMEWORK,
196*8823STruong.Q.Nguyen@Sun.COM 			    scf_strerror(scf_error()));
197*8823STruong.Q.Nguyen@Sun.COM 			abort();
198*8823STruong.Q.Nguyen@Sun.COM 		}
199*8823STruong.Q.Nguyen@Sun.COM 	}
200*8823STruong.Q.Nguyen@Sun.COM }
201*8823STruong.Q.Nguyen@Sun.COM 
202*8823STruong.Q.Nguyen@Sun.COM /*
203*8823STruong.Q.Nguyen@Sun.COM  * If the repository connection is lost, rebind and re-setup repository
204*8823STruong.Q.Nguyen@Sun.COM  * notification. During the repository connection outage, services that
205*8823STruong.Q.Nguyen@Sun.COM  * changed states wouldn't get the corresponding firewall update. To make
206*8823STruong.Q.Nguyen@Sun.COM  * we're not out of sync, update the entire system firewall configuration,
207*8823STruong.Q.Nguyen@Sun.COM  * invoke ipfilter_update(IPFILTER_FMRI).
208*8823STruong.Q.Nguyen@Sun.COM  */
209*8823STruong.Q.Nguyen@Sun.COM static void
repository_setup()210*8823STruong.Q.Nguyen@Sun.COM repository_setup()
211*8823STruong.Q.Nguyen@Sun.COM {
212*8823STruong.Q.Nguyen@Sun.COM 	repository_rebind(h);
213*8823STruong.Q.Nguyen@Sun.COM 	repository_notify_setup(h);
214*8823STruong.Q.Nguyen@Sun.COM 	if (ipfilter_update(IPFILTER_FMRI) == -1) {
215*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_ERR | LOG_DAEMON,
216*8823STruong.Q.Nguyen@Sun.COM 		    "Failed to reconfigure system firewall.\n");
217*8823STruong.Q.Nguyen@Sun.COM 	}
218*8823STruong.Q.Nguyen@Sun.COM }
219*8823STruong.Q.Nguyen@Sun.COM 
220*8823STruong.Q.Nguyen@Sun.COM static int
pg_get_prop_value(const scf_propertygroup_t * pg,const char * pname,scf_value_t * v)221*8823STruong.Q.Nguyen@Sun.COM pg_get_prop_value(const scf_propertygroup_t *pg, const char *pname,
222*8823STruong.Q.Nguyen@Sun.COM     scf_value_t *v)
223*8823STruong.Q.Nguyen@Sun.COM {
224*8823STruong.Q.Nguyen@Sun.COM 	if (pg == NULL || pname == NULL || v == NULL)
225*8823STruong.Q.Nguyen@Sun.COM 		return (-1);
226*8823STruong.Q.Nguyen@Sun.COM 
227*8823STruong.Q.Nguyen@Sun.COM 	if (scf_pg_get_property(pg, pname, scratch_prop) == -1 ||
228*8823STruong.Q.Nguyen@Sun.COM 	    scf_property_get_value(scratch_prop, v) == -1) {
229*8823STruong.Q.Nguyen@Sun.COM 		switch (scf_error()) {
230*8823STruong.Q.Nguyen@Sun.COM 		case SCF_ERROR_NOT_FOUND:
231*8823STruong.Q.Nguyen@Sun.COM 		case SCF_ERROR_DELETED:
232*8823STruong.Q.Nguyen@Sun.COM 			break;
233*8823STruong.Q.Nguyen@Sun.COM 
234*8823STruong.Q.Nguyen@Sun.COM 		default:
235*8823STruong.Q.Nguyen@Sun.COM 			syslog(LOG_ERR | LOG_DAEMON,
236*8823STruong.Q.Nguyen@Sun.COM 			    "scf_pg_get_property failed for %s: %s\n",
237*8823STruong.Q.Nguyen@Sun.COM 			    pname, scf_strerror(scf_error()));
238*8823STruong.Q.Nguyen@Sun.COM 		}
239*8823STruong.Q.Nguyen@Sun.COM 		return (-1);
240*8823STruong.Q.Nguyen@Sun.COM 	}
241*8823STruong.Q.Nguyen@Sun.COM 	return (0);
242*8823STruong.Q.Nguyen@Sun.COM }
243*8823STruong.Q.Nguyen@Sun.COM 
244*8823STruong.Q.Nguyen@Sun.COM static int
is_correct_event(const char * fmri,const scf_propertygroup_t * pg,const boolean_t isrpc)245*8823STruong.Q.Nguyen@Sun.COM is_correct_event(const char *fmri, const scf_propertygroup_t *pg,
246*8823STruong.Q.Nguyen@Sun.COM     const boolean_t isrpc)
247*8823STruong.Q.Nguyen@Sun.COM {
248*8823STruong.Q.Nguyen@Sun.COM 	char *state = NULL;
249*8823STruong.Q.Nguyen@Sun.COM 	const char **proplist = all_props;
250*8823STruong.Q.Nguyen@Sun.COM 	int prop_cnt = ALL_PROPS_CNT;
251*8823STruong.Q.Nguyen@Sun.COM 
252*8823STruong.Q.Nguyen@Sun.COM 	int i, ret = 0;
253*8823STruong.Q.Nguyen@Sun.COM 
254*8823STruong.Q.Nguyen@Sun.COM 	if (scf_pg_get_name(pg, scratch_name, max_scf_name_size) < 0) {
255*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_ERR | LOG_DAEMON, "scf_pg_get_name failed: %s\n",
256*8823STruong.Q.Nguyen@Sun.COM 		    scf_strerror(scf_error()));
257*8823STruong.Q.Nguyen@Sun.COM 		return (-1);
258*8823STruong.Q.Nguyen@Sun.COM 	}
259*8823STruong.Q.Nguyen@Sun.COM 
260*8823STruong.Q.Nguyen@Sun.COM 	/*
261*8823STruong.Q.Nguyen@Sun.COM 	 * We care about enable, disable, and refresh since that's
262*8823STruong.Q.Nguyen@Sun.COM 	 * when we activate, deactivate, or change firewall policy.
263*8823STruong.Q.Nguyen@Sun.COM 	 *
264*8823STruong.Q.Nguyen@Sun.COM 	 *  - enable/disable -> change in "general" or "general_ovr"
265*8823STruong.Q.Nguyen@Sun.COM 	 *  - refresh/restart -> change in "restarter_actions"
266*8823STruong.Q.Nguyen@Sun.COM 	 */
267*8823STruong.Q.Nguyen@Sun.COM 	if (strcmp(scratch_name, SCF_PG_GENERAL) == 0 ||
268*8823STruong.Q.Nguyen@Sun.COM 	    strcmp(scratch_name, SCF_PG_GENERAL_OVR) == 0) {
269*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_DEBUG | LOG_DAEMON, "Action: %s", scratch_name);
270*8823STruong.Q.Nguyen@Sun.COM 		return (1);
271*8823STruong.Q.Nguyen@Sun.COM 	}
272*8823STruong.Q.Nguyen@Sun.COM 
273*8823STruong.Q.Nguyen@Sun.COM 	if ((state = smf_get_state(fmri)) == NULL) {
274*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_ERR | LOG_DAEMON, "smf_get_state failed for %s: "
275*8823STruong.Q.Nguyen@Sun.COM 		    "%s\n", fmri, scf_strerror(scf_error()));
276*8823STruong.Q.Nguyen@Sun.COM 		return (-1);
277*8823STruong.Q.Nguyen@Sun.COM 	}
278*8823STruong.Q.Nguyen@Sun.COM 
279*8823STruong.Q.Nguyen@Sun.COM 	syslog(LOG_DEBUG | LOG_DAEMON, "%s STATE: %s \n", fmri, state);
280*8823STruong.Q.Nguyen@Sun.COM 	if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
281*8823STruong.Q.Nguyen@Sun.COM 		proplist = maint_props;
282*8823STruong.Q.Nguyen@Sun.COM 		prop_cnt = MAINT_PROPS_CNT;
283*8823STruong.Q.Nguyen@Sun.COM 	}
284*8823STruong.Q.Nguyen@Sun.COM 
285*8823STruong.Q.Nguyen@Sun.COM 	/*
286*8823STruong.Q.Nguyen@Sun.COM 	 * Only concerned with refresh, restart, and maint on|off actions.
287*8823STruong.Q.Nguyen@Sun.COM 	 * RPC services are restarted whenever rpc/bind restarts so it's
288*8823STruong.Q.Nguyen@Sun.COM 	 * an automatic valid event for RPC services.
289*8823STruong.Q.Nguyen@Sun.COM 	 */
290*8823STruong.Q.Nguyen@Sun.COM 	if (isrpc) {
291*8823STruong.Q.Nguyen@Sun.COM 		ret = 1;
292*8823STruong.Q.Nguyen@Sun.COM 		goto out;
293*8823STruong.Q.Nguyen@Sun.COM 	} else if (strcmp(scratch_name, SCF_PG_RESTARTER_ACTIONS) == 0) {
294*8823STruong.Q.Nguyen@Sun.COM 		for (i = 0; i < prop_cnt; i++) {
295*8823STruong.Q.Nguyen@Sun.COM 			if (pg_get_prop_value(pg, proplist[i],
296*8823STruong.Q.Nguyen@Sun.COM 			    scratch_v) == 0) {
297*8823STruong.Q.Nguyen@Sun.COM 				syslog(LOG_DEBUG | LOG_DAEMON, "Action: %s/%s",
298*8823STruong.Q.Nguyen@Sun.COM 				    scratch_name, proplist[i]);
299*8823STruong.Q.Nguyen@Sun.COM 
300*8823STruong.Q.Nguyen@Sun.COM 				ret = 1;
301*8823STruong.Q.Nguyen@Sun.COM 				goto out;
302*8823STruong.Q.Nguyen@Sun.COM 			}
303*8823STruong.Q.Nguyen@Sun.COM 		}
304*8823STruong.Q.Nguyen@Sun.COM 	}
305*8823STruong.Q.Nguyen@Sun.COM 
306*8823STruong.Q.Nguyen@Sun.COM out:
307*8823STruong.Q.Nguyen@Sun.COM 	if (state)
308*8823STruong.Q.Nguyen@Sun.COM 		free(state);
309*8823STruong.Q.Nguyen@Sun.COM 
310*8823STruong.Q.Nguyen@Sun.COM 	return (ret);
311*8823STruong.Q.Nguyen@Sun.COM }
312*8823STruong.Q.Nguyen@Sun.COM 
313*8823STruong.Q.Nguyen@Sun.COM static int
ipfilter_update(const char * fmri)314*8823STruong.Q.Nguyen@Sun.COM ipfilter_update(const char *fmri)
315*8823STruong.Q.Nguyen@Sun.COM {
316*8823STruong.Q.Nguyen@Sun.COM 	pid_t pid;
317*8823STruong.Q.Nguyen@Sun.COM 	int status, ret = 0;
318*8823STruong.Q.Nguyen@Sun.COM 
319*8823STruong.Q.Nguyen@Sun.COM 	syslog(LOG_DEBUG | LOG_DAEMON, "ipfilter_update: %s\n", fmri);
320*8823STruong.Q.Nguyen@Sun.COM 
321*8823STruong.Q.Nguyen@Sun.COM 	/*
322*8823STruong.Q.Nguyen@Sun.COM 	 * Start refresh in another process
323*8823STruong.Q.Nguyen@Sun.COM 	 */
324*8823STruong.Q.Nguyen@Sun.COM 	if ((pid = fork1()) < 0) {
325*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_ERR | LOG_DAEMON, "Couldn't fork to refresh "
326*8823STruong.Q.Nguyen@Sun.COM 		    "ipfilter for %s: %s", fmri, strerror(errno));
327*8823STruong.Q.Nguyen@Sun.COM 		ret = 1;
328*8823STruong.Q.Nguyen@Sun.COM 		goto out;
329*8823STruong.Q.Nguyen@Sun.COM 	}
330*8823STruong.Q.Nguyen@Sun.COM 
331*8823STruong.Q.Nguyen@Sun.COM 	if (pid == 0) {
332*8823STruong.Q.Nguyen@Sun.COM 		if (execl(IPF_UPDATE_CMD, IPF_UPDATE_CMD, "fw_update", fmri,
333*8823STruong.Q.Nguyen@Sun.COM 		    NULL) == -1)
334*8823STruong.Q.Nguyen@Sun.COM 			syslog(LOG_ERR | LOG_DAEMON, "execl() failed for "
335*8823STruong.Q.Nguyen@Sun.COM 			    "%s: %s", fmri, strerror(errno));
336*8823STruong.Q.Nguyen@Sun.COM 
337*8823STruong.Q.Nguyen@Sun.COM 		exit(1);
338*8823STruong.Q.Nguyen@Sun.COM 	}
339*8823STruong.Q.Nguyen@Sun.COM 
340*8823STruong.Q.Nguyen@Sun.COM 	/*
341*8823STruong.Q.Nguyen@Sun.COM 	 * Parent - only one update at a time.
342*8823STruong.Q.Nguyen@Sun.COM 	 */
343*8823STruong.Q.Nguyen@Sun.COM 	(void) wait(&status);
344*8823STruong.Q.Nguyen@Sun.COM 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
345*8823STruong.Q.Nguyen@Sun.COM 		ret = 1;
346*8823STruong.Q.Nguyen@Sun.COM 
347*8823STruong.Q.Nguyen@Sun.COM out:
348*8823STruong.Q.Nguyen@Sun.COM 	if (ret == 1)
349*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_ERR | LOG_DAEMON, "Firewall update failed "
350*8823STruong.Q.Nguyen@Sun.COM 		    "for: %s\n", fmri);
351*8823STruong.Q.Nguyen@Sun.COM 
352*8823STruong.Q.Nguyen@Sun.COM 	return (ret);
353*8823STruong.Q.Nguyen@Sun.COM }
354*8823STruong.Q.Nguyen@Sun.COM 
355*8823STruong.Q.Nguyen@Sun.COM /*
356*8823STruong.Q.Nguyen@Sun.COM  * Determine whether a given instance is a RPC service. Repository and
357*8823STruong.Q.Nguyen@Sun.COM  * libscf errors are treated as if the service isn't an RPC service,
358*8823STruong.Q.Nguyen@Sun.COM  * returning B_FALSE to indicate validation failure.
359*8823STruong.Q.Nguyen@Sun.COM  */
360*8823STruong.Q.Nguyen@Sun.COM static boolean_t
service_is_rpc(const scf_instance_t * inst)361*8823STruong.Q.Nguyen@Sun.COM service_is_rpc(const scf_instance_t *inst)
362*8823STruong.Q.Nguyen@Sun.COM {
363*8823STruong.Q.Nguyen@Sun.COM 	scf_snapshot_t *lsnap = NULL;
364*8823STruong.Q.Nguyen@Sun.COM 	uint8_t	isrpc;
365*8823STruong.Q.Nguyen@Sun.COM 
366*8823STruong.Q.Nguyen@Sun.COM 	if (scf_instance_get_snapshot(inst, SCF_SNAPSHOT_RUNNING, snap) != 0) {
367*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_DEBUG | LOG_DAEMON,
368*8823STruong.Q.Nguyen@Sun.COM 		    "Could not get running snapshot, using editing value\n");
369*8823STruong.Q.Nguyen@Sun.COM 	} else {
370*8823STruong.Q.Nguyen@Sun.COM 		lsnap = snap;
371*8823STruong.Q.Nguyen@Sun.COM 	}
372*8823STruong.Q.Nguyen@Sun.COM 
373*8823STruong.Q.Nguyen@Sun.COM 	if (scf_instance_get_pg_composed(inst, lsnap, SCF_PG_INETD,
374*8823STruong.Q.Nguyen@Sun.COM 	    scratch_pg) == -1) {
375*8823STruong.Q.Nguyen@Sun.COM 		switch (scf_error()) {
376*8823STruong.Q.Nguyen@Sun.COM 		case SCF_ERROR_NOT_FOUND:
377*8823STruong.Q.Nguyen@Sun.COM 		case SCF_ERROR_DELETED:
378*8823STruong.Q.Nguyen@Sun.COM 			break;
379*8823STruong.Q.Nguyen@Sun.COM 
380*8823STruong.Q.Nguyen@Sun.COM 		default:
381*8823STruong.Q.Nguyen@Sun.COM 			syslog(LOG_ERR | LOG_DAEMON,
382*8823STruong.Q.Nguyen@Sun.COM 			    "scf_instance_get_pg_composed failed: %s\n",
383*8823STruong.Q.Nguyen@Sun.COM 			    scf_strerror(scf_error()));
384*8823STruong.Q.Nguyen@Sun.COM 			return (B_FALSE);
385*8823STruong.Q.Nguyen@Sun.COM 		}
386*8823STruong.Q.Nguyen@Sun.COM 
387*8823STruong.Q.Nguyen@Sun.COM 		if (scf_instance_get_pg_composed(inst, lsnap,
388*8823STruong.Q.Nguyen@Sun.COM 		    SCF_PG_FW_CONTEXT, scratch_pg) == -1) {
389*8823STruong.Q.Nguyen@Sun.COM 			switch (scf_error()) {
390*8823STruong.Q.Nguyen@Sun.COM 			case SCF_ERROR_NOT_FOUND:
391*8823STruong.Q.Nguyen@Sun.COM 			case SCF_ERROR_DELETED:
392*8823STruong.Q.Nguyen@Sun.COM 				break;
393*8823STruong.Q.Nguyen@Sun.COM 
394*8823STruong.Q.Nguyen@Sun.COM 			default:
395*8823STruong.Q.Nguyen@Sun.COM 				syslog(LOG_ERR | LOG_DAEMON,
396*8823STruong.Q.Nguyen@Sun.COM 				    "scf_instance_get_pg_composed failed: %s\n",
397*8823STruong.Q.Nguyen@Sun.COM 				    scf_strerror(scf_error()));
398*8823STruong.Q.Nguyen@Sun.COM 			}
399*8823STruong.Q.Nguyen@Sun.COM 			return (B_FALSE);
400*8823STruong.Q.Nguyen@Sun.COM 		}
401*8823STruong.Q.Nguyen@Sun.COM 	}
402*8823STruong.Q.Nguyen@Sun.COM 
403*8823STruong.Q.Nguyen@Sun.COM 	if (pg_get_prop_value(scratch_pg, SCF_PROPERTY_ISRPC, scratch_v) == -1)
404*8823STruong.Q.Nguyen@Sun.COM 		return (B_FALSE);
405*8823STruong.Q.Nguyen@Sun.COM 
406*8823STruong.Q.Nguyen@Sun.COM 	if (scf_value_get_boolean(scratch_v, &isrpc) == -1) {
407*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_ERR | LOG_DAEMON, "scf_value_get_boolean failed: "
408*8823STruong.Q.Nguyen@Sun.COM 		    "%s\n", scf_strerror(scf_error()));
409*8823STruong.Q.Nguyen@Sun.COM 		return (B_FALSE);
410*8823STruong.Q.Nguyen@Sun.COM 	}
411*8823STruong.Q.Nguyen@Sun.COM 
412*8823STruong.Q.Nguyen@Sun.COM 	if (isrpc)
413*8823STruong.Q.Nguyen@Sun.COM 		return (B_TRUE);
414*8823STruong.Q.Nguyen@Sun.COM 	else
415*8823STruong.Q.Nguyen@Sun.COM 		return (B_FALSE);
416*8823STruong.Q.Nguyen@Sun.COM }
417*8823STruong.Q.Nguyen@Sun.COM 
418*8823STruong.Q.Nguyen@Sun.COM static int
instance_has_firewall(scf_instance_t * inst)419*8823STruong.Q.Nguyen@Sun.COM instance_has_firewall(scf_instance_t *inst)
420*8823STruong.Q.Nguyen@Sun.COM {
421*8823STruong.Q.Nguyen@Sun.COM 	scf_snapshot_t *lsnap = NULL;
422*8823STruong.Q.Nguyen@Sun.COM 
423*8823STruong.Q.Nguyen@Sun.COM 	if (scf_instance_get_snapshot(inst, SCF_SNAPSHOT_RUNNING, snap) == -1) {
424*8823STruong.Q.Nguyen@Sun.COM 		switch (scf_error()) {
425*8823STruong.Q.Nguyen@Sun.COM 		case SCF_ERROR_CONNECTION_BROKEN:
426*8823STruong.Q.Nguyen@Sun.COM 			syslog(LOG_ERR | LOG_DAEMON,
427*8823STruong.Q.Nguyen@Sun.COM 			    "scf_instance_get_snapshot failed: %s\n",
428*8823STruong.Q.Nguyen@Sun.COM 			    scf_strerror(scf_error()));
429*8823STruong.Q.Nguyen@Sun.COM 			repository_setup();
430*8823STruong.Q.Nguyen@Sun.COM 			return (-1);
431*8823STruong.Q.Nguyen@Sun.COM 
432*8823STruong.Q.Nguyen@Sun.COM 		case SCF_ERROR_DELETED:
433*8823STruong.Q.Nguyen@Sun.COM 		default:
434*8823STruong.Q.Nguyen@Sun.COM 			/*
435*8823STruong.Q.Nguyen@Sun.COM 			 * If running snapshot is not available for
436*8823STruong.Q.Nguyen@Sun.COM 			 * other reasons, fall back to current values.
437*8823STruong.Q.Nguyen@Sun.COM 			 */
438*8823STruong.Q.Nguyen@Sun.COM 			syslog(LOG_DEBUG | LOG_DAEMON, "Could not get "
439*8823STruong.Q.Nguyen@Sun.COM 			    "running snapshot, using current value\n");
440*8823STruong.Q.Nguyen@Sun.COM 		}
441*8823STruong.Q.Nguyen@Sun.COM 	} else {
442*8823STruong.Q.Nguyen@Sun.COM 		lsnap = snap;
443*8823STruong.Q.Nguyen@Sun.COM 	}
444*8823STruong.Q.Nguyen@Sun.COM 
445*8823STruong.Q.Nguyen@Sun.COM 	/*
446*8823STruong.Q.Nguyen@Sun.COM 	 * Update service's IPfilter configuration if either
447*8823STruong.Q.Nguyen@Sun.COM 	 * SCF_PG_FW_CONTEXT or SCF_PG_FW_CONFIG exists.
448*8823STruong.Q.Nguyen@Sun.COM 	 */
449*8823STruong.Q.Nguyen@Sun.COM 	if (scf_instance_get_pg_composed(inst, lsnap, SCF_PG_FW_CONTEXT,
450*8823STruong.Q.Nguyen@Sun.COM 	    scratch_pg) == 0) {
451*8823STruong.Q.Nguyen@Sun.COM 		return (1);
452*8823STruong.Q.Nguyen@Sun.COM 	} else {
453*8823STruong.Q.Nguyen@Sun.COM 		switch (scf_error()) {
454*8823STruong.Q.Nguyen@Sun.COM 		case SCF_ERROR_NOT_FOUND:
455*8823STruong.Q.Nguyen@Sun.COM 		case SCF_ERROR_DELETED:
456*8823STruong.Q.Nguyen@Sun.COM 			break;
457*8823STruong.Q.Nguyen@Sun.COM 
458*8823STruong.Q.Nguyen@Sun.COM 		case SCF_ERROR_CONNECTION_BROKEN:
459*8823STruong.Q.Nguyen@Sun.COM 			repository_setup();
460*8823STruong.Q.Nguyen@Sun.COM 			/* FALLTHROUGH */
461*8823STruong.Q.Nguyen@Sun.COM 		default:
462*8823STruong.Q.Nguyen@Sun.COM 			syslog(LOG_ERR | LOG_DAEMON,
463*8823STruong.Q.Nguyen@Sun.COM 			    "scf_instance_get_pg_composed failed: %s\n",
464*8823STruong.Q.Nguyen@Sun.COM 			    scf_strerror(scf_error()));
465*8823STruong.Q.Nguyen@Sun.COM 			return (-1);
466*8823STruong.Q.Nguyen@Sun.COM 		}
467*8823STruong.Q.Nguyen@Sun.COM 	}
468*8823STruong.Q.Nguyen@Sun.COM 
469*8823STruong.Q.Nguyen@Sun.COM 	if (scf_instance_get_pg_composed(inst, lsnap, SCF_PG_FW_CONFIG,
470*8823STruong.Q.Nguyen@Sun.COM 	    scratch_pg) == -1) {
471*8823STruong.Q.Nguyen@Sun.COM 		/*
472*8823STruong.Q.Nguyen@Sun.COM 		 * It's either a non-firewall service or a failure to
473*8823STruong.Q.Nguyen@Sun.COM 		 * read firewall pg, just continue and listen for
474*8823STruong.Q.Nguyen@Sun.COM 		 * future events.
475*8823STruong.Q.Nguyen@Sun.COM 		 */
476*8823STruong.Q.Nguyen@Sun.COM 		switch (scf_error()) {
477*8823STruong.Q.Nguyen@Sun.COM 		case SCF_ERROR_NOT_FOUND:
478*8823STruong.Q.Nguyen@Sun.COM 		case SCF_ERROR_DELETED:
479*8823STruong.Q.Nguyen@Sun.COM 			return (0);
480*8823STruong.Q.Nguyen@Sun.COM 
481*8823STruong.Q.Nguyen@Sun.COM 		case SCF_ERROR_CONNECTION_BROKEN:
482*8823STruong.Q.Nguyen@Sun.COM 			repository_setup();
483*8823STruong.Q.Nguyen@Sun.COM 			/* FALLTHROUGH */
484*8823STruong.Q.Nguyen@Sun.COM 		default:
485*8823STruong.Q.Nguyen@Sun.COM 			syslog(LOG_ERR | LOG_DAEMON,
486*8823STruong.Q.Nguyen@Sun.COM 			    "scf_instance_get_pg_composed failed: %s\n",
487*8823STruong.Q.Nguyen@Sun.COM 			    scf_strerror(scf_error()));
488*8823STruong.Q.Nguyen@Sun.COM 			return (-1);
489*8823STruong.Q.Nguyen@Sun.COM 		}
490*8823STruong.Q.Nguyen@Sun.COM 	}
491*8823STruong.Q.Nguyen@Sun.COM 	return (1);
492*8823STruong.Q.Nguyen@Sun.COM }
493*8823STruong.Q.Nguyen@Sun.COM 
494*8823STruong.Q.Nguyen@Sun.COM static int
repository_event_process(scf_propertygroup_t * pg)495*8823STruong.Q.Nguyen@Sun.COM repository_event_process(scf_propertygroup_t *pg)
496*8823STruong.Q.Nguyen@Sun.COM {
497*8823STruong.Q.Nguyen@Sun.COM 	boolean_t isrpc = B_FALSE;
498*8823STruong.Q.Nguyen@Sun.COM 	int res;
499*8823STruong.Q.Nguyen@Sun.COM 
500*8823STruong.Q.Nguyen@Sun.COM 	/*
501*8823STruong.Q.Nguyen@Sun.COM 	 * Figure out it's a firewall capable instance and call ipfilter_update
502*8823STruong.Q.Nguyen@Sun.COM 	 * if it is.
503*8823STruong.Q.Nguyen@Sun.COM 	 */
504*8823STruong.Q.Nguyen@Sun.COM 	if (scf_pg_get_parent_instance(pg, inst) == -1) {
505*8823STruong.Q.Nguyen@Sun.COM 		/* Not an error if pg doesn't belong to a valid instance */
506*8823STruong.Q.Nguyen@Sun.COM 		if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) {
507*8823STruong.Q.Nguyen@Sun.COM 			return (0);
508*8823STruong.Q.Nguyen@Sun.COM 		}
509*8823STruong.Q.Nguyen@Sun.COM 
510*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_ERR | LOG_DAEMON, "scf_pg_get_parent_instance "
511*8823STruong.Q.Nguyen@Sun.COM 		    "failed: %s\n", scf_strerror(scf_error()));
512*8823STruong.Q.Nguyen@Sun.COM 
513*8823STruong.Q.Nguyen@Sun.COM 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN)
514*8823STruong.Q.Nguyen@Sun.COM 			repository_setup();
515*8823STruong.Q.Nguyen@Sun.COM 
516*8823STruong.Q.Nguyen@Sun.COM 		return (1);
517*8823STruong.Q.Nguyen@Sun.COM 	}
518*8823STruong.Q.Nguyen@Sun.COM 
519*8823STruong.Q.Nguyen@Sun.COM 	if (scf_instance_to_fmri(inst, scratch_fmri, max_scf_fmri_size) == -1) {
520*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_ERR | LOG_DAEMON, "scf_instance_to_fmri "
521*8823STruong.Q.Nguyen@Sun.COM 		    "failed: %s\n", scf_strerror(scf_error()));
522*8823STruong.Q.Nguyen@Sun.COM 
523*8823STruong.Q.Nguyen@Sun.COM 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN)
524*8823STruong.Q.Nguyen@Sun.COM 			repository_setup();
525*8823STruong.Q.Nguyen@Sun.COM 
526*8823STruong.Q.Nguyen@Sun.COM 		return (1);
527*8823STruong.Q.Nguyen@Sun.COM 	}
528*8823STruong.Q.Nguyen@Sun.COM 
529*8823STruong.Q.Nguyen@Sun.COM 	if (strcmp(scratch_fmri, IPFILTER_FMRI) == 0) {
530*8823STruong.Q.Nguyen@Sun.COM 		return (0);
531*8823STruong.Q.Nguyen@Sun.COM 	}
532*8823STruong.Q.Nguyen@Sun.COM 
533*8823STruong.Q.Nguyen@Sun.COM 	isrpc = service_is_rpc(inst);
534*8823STruong.Q.Nguyen@Sun.COM 
535*8823STruong.Q.Nguyen@Sun.COM 	/*
536*8823STruong.Q.Nguyen@Sun.COM 	 * If it's not an event we're interested in, returns success.
537*8823STruong.Q.Nguyen@Sun.COM 	 */
538*8823STruong.Q.Nguyen@Sun.COM 	res = is_correct_event(scratch_fmri, pg, isrpc);
539*8823STruong.Q.Nguyen@Sun.COM 	if (res == -1) {
540*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_ERR | LOG_DAEMON,
541*8823STruong.Q.Nguyen@Sun.COM 		    "is_correct_event failed for %s.\n", scratch_fmri);
542*8823STruong.Q.Nguyen@Sun.COM 		return (1);
543*8823STruong.Q.Nguyen@Sun.COM 	} else if (res == 0) {
544*8823STruong.Q.Nguyen@Sun.COM 		return (0);
545*8823STruong.Q.Nguyen@Sun.COM 	}
546*8823STruong.Q.Nguyen@Sun.COM 
547*8823STruong.Q.Nguyen@Sun.COM 	/*
548*8823STruong.Q.Nguyen@Sun.COM 	 * Proceed only if instance has firewall policy.
549*8823STruong.Q.Nguyen@Sun.COM 	 */
550*8823STruong.Q.Nguyen@Sun.COM 	res = instance_has_firewall(inst);
551*8823STruong.Q.Nguyen@Sun.COM 	if (res == -1) {
552*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_ERR | LOG_DAEMON,
553*8823STruong.Q.Nguyen@Sun.COM 		    "instance_has_firewall failed for %s.\n", scratch_fmri);
554*8823STruong.Q.Nguyen@Sun.COM 		return (1);
555*8823STruong.Q.Nguyen@Sun.COM 	} else if (res == 0) {
556*8823STruong.Q.Nguyen@Sun.COM 		return (0);
557*8823STruong.Q.Nguyen@Sun.COM 	}
558*8823STruong.Q.Nguyen@Sun.COM 
559*8823STruong.Q.Nguyen@Sun.COM 	if (ipfilter_update(scratch_fmri) == -1) {
560*8823STruong.Q.Nguyen@Sun.COM 		return (1);
561*8823STruong.Q.Nguyen@Sun.COM 	}
562*8823STruong.Q.Nguyen@Sun.COM 
563*8823STruong.Q.Nguyen@Sun.COM 	return (0);
564*8823STruong.Q.Nguyen@Sun.COM }
565*8823STruong.Q.Nguyen@Sun.COM 
566*8823STruong.Q.Nguyen@Sun.COM static int
repository_event_wait()567*8823STruong.Q.Nguyen@Sun.COM repository_event_wait()
568*8823STruong.Q.Nguyen@Sun.COM {
569*8823STruong.Q.Nguyen@Sun.COM 	scf_propertygroup_t *pg;
570*8823STruong.Q.Nguyen@Sun.COM 	char *fmri, *scratch;
571*8823STruong.Q.Nguyen@Sun.COM 	const char *inst_name, *pg_name;
572*8823STruong.Q.Nguyen@Sun.COM 	ssize_t res;
573*8823STruong.Q.Nguyen@Sun.COM 
574*8823STruong.Q.Nguyen@Sun.COM 	if ((fmri = umem_alloc(max_scf_fmri_size, UMEM_DEFAULT)) == NULL) {
575*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_ERR | LOG_DAEMON, "Out of memory");
576*8823STruong.Q.Nguyen@Sun.COM 		return (1);
577*8823STruong.Q.Nguyen@Sun.COM 	}
578*8823STruong.Q.Nguyen@Sun.COM 
579*8823STruong.Q.Nguyen@Sun.COM 	if ((scratch = umem_alloc(max_scf_fmri_size, UMEM_DEFAULT)) == NULL) {
580*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_ERR | LOG_DAEMON, "Out of memory");
581*8823STruong.Q.Nguyen@Sun.COM 		return (1);
582*8823STruong.Q.Nguyen@Sun.COM 	}
583*8823STruong.Q.Nguyen@Sun.COM 
584*8823STruong.Q.Nguyen@Sun.COM 	if ((pg = scf_pg_create(h)) == NULL) {
585*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_ERR | LOG_DAEMON, "scf_pg_create failed: %s\n",
586*8823STruong.Q.Nguyen@Sun.COM 		    scf_strerror(scf_error()));
587*8823STruong.Q.Nguyen@Sun.COM 		return (1);
588*8823STruong.Q.Nguyen@Sun.COM 	}
589*8823STruong.Q.Nguyen@Sun.COM 
590*8823STruong.Q.Nguyen@Sun.COM 	repository_notify_setup(h);
591*8823STruong.Q.Nguyen@Sun.COM 
592*8823STruong.Q.Nguyen@Sun.COM 	for (;;) {
593*8823STruong.Q.Nguyen@Sun.COM 		/*
594*8823STruong.Q.Nguyen@Sun.COM 		 * Calling _scf_notify_wait which will block this thread
595*8823STruong.Q.Nguyen@Sun.COM 		 * until it's notified of a framework event.
596*8823STruong.Q.Nguyen@Sun.COM 		 *
597*8823STruong.Q.Nguyen@Sun.COM 		 * Note: fmri is only set on delete events.
598*8823STruong.Q.Nguyen@Sun.COM 		 */
599*8823STruong.Q.Nguyen@Sun.COM 		res = _scf_notify_wait(pg, fmri, max_scf_fmri_size);
600*8823STruong.Q.Nguyen@Sun.COM 		if (res < 0) {
601*8823STruong.Q.Nguyen@Sun.COM 			syslog(LOG_ERR | LOG_DAEMON, "_scf_notify_wait "
602*8823STruong.Q.Nguyen@Sun.COM 			    "failed: %s\n", scf_strerror(scf_error()));
603*8823STruong.Q.Nguyen@Sun.COM 			repository_setup();
604*8823STruong.Q.Nguyen@Sun.COM 		} else if (res == 0) {
605*8823STruong.Q.Nguyen@Sun.COM 			if (repository_event_process(pg))
606*8823STruong.Q.Nguyen@Sun.COM 				syslog(LOG_ERR | LOG_DAEMON, "Service may have "
607*8823STruong.Q.Nguyen@Sun.COM 				    "incorrect IPfilter configuration\n");
608*8823STruong.Q.Nguyen@Sun.COM 		} else {
609*8823STruong.Q.Nguyen@Sun.COM 			/*
610*8823STruong.Q.Nguyen@Sun.COM 			 * The received event is a deletion of a service,
611*8823STruong.Q.Nguyen@Sun.COM 			 * instance or pg. If it's a deletion of an instance,
612*8823STruong.Q.Nguyen@Sun.COM 			 * update the instance's IPfilter configuration.
613*8823STruong.Q.Nguyen@Sun.COM 			 */
614*8823STruong.Q.Nguyen@Sun.COM 			syslog(LOG_DEBUG | LOG_DAEMON, "Deleted: %s", fmri);
615*8823STruong.Q.Nguyen@Sun.COM 
616*8823STruong.Q.Nguyen@Sun.COM 			(void) strlcpy(scratch, fmri, max_scf_fmri_size);
617*8823STruong.Q.Nguyen@Sun.COM 			if (scf_parse_svc_fmri(scratch, NULL, NULL, &inst_name,
618*8823STruong.Q.Nguyen@Sun.COM 			    &pg_name, NULL) != SCF_SUCCESS)
619*8823STruong.Q.Nguyen@Sun.COM 				continue;
620*8823STruong.Q.Nguyen@Sun.COM 
621*8823STruong.Q.Nguyen@Sun.COM 			if (inst_name != NULL && pg_name == NULL) {
622*8823STruong.Q.Nguyen@Sun.COM 				(void) ipfilter_update(fmri);
623*8823STruong.Q.Nguyen@Sun.COM 			}
624*8823STruong.Q.Nguyen@Sun.COM 		}
625*8823STruong.Q.Nguyen@Sun.COM 	}
626*8823STruong.Q.Nguyen@Sun.COM 
627*8823STruong.Q.Nguyen@Sun.COM 	/*NOTREACHED*/
628*8823STruong.Q.Nguyen@Sun.COM }
629*8823STruong.Q.Nguyen@Sun.COM 
630*8823STruong.Q.Nguyen@Sun.COM int
main()631*8823STruong.Q.Nguyen@Sun.COM main()
632*8823STruong.Q.Nguyen@Sun.COM {
633*8823STruong.Q.Nguyen@Sun.COM 	if (daemonize_self() == 1)
634*8823STruong.Q.Nguyen@Sun.COM 		return (1);
635*8823STruong.Q.Nguyen@Sun.COM 
636*8823STruong.Q.Nguyen@Sun.COM 	max_scf_fmri_size = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1;
637*8823STruong.Q.Nguyen@Sun.COM 	max_scf_name_size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
638*8823STruong.Q.Nguyen@Sun.COM 
639*8823STruong.Q.Nguyen@Sun.COM 	assert(max_scf_fmri_size > 0);
640*8823STruong.Q.Nguyen@Sun.COM 	assert(max_scf_name_size > 0);
641*8823STruong.Q.Nguyen@Sun.COM 
642*8823STruong.Q.Nguyen@Sun.COM 	if ((h = scf_handle_create(SCF_VERSION)) == NULL) {
643*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_ERR | LOG_DAEMON, "scf_handle_create failed: %s\n",
644*8823STruong.Q.Nguyen@Sun.COM 		    scf_strerror(scf_error()));
645*8823STruong.Q.Nguyen@Sun.COM 		return (1);
646*8823STruong.Q.Nguyen@Sun.COM 	}
647*8823STruong.Q.Nguyen@Sun.COM 
648*8823STruong.Q.Nguyen@Sun.COM 	repository_rebind(h);
649*8823STruong.Q.Nguyen@Sun.COM 
650*8823STruong.Q.Nguyen@Sun.COM 	scratch_fmri = umem_alloc(max_scf_fmri_size, UMEM_DEFAULT);
651*8823STruong.Q.Nguyen@Sun.COM 	scratch_name = umem_alloc(max_scf_name_size, UMEM_DEFAULT);
652*8823STruong.Q.Nguyen@Sun.COM 
653*8823STruong.Q.Nguyen@Sun.COM 	if (scratch_fmri == NULL || scratch_name == NULL) {
654*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_ERR | LOG_DAEMON, "Out of memory");
655*8823STruong.Q.Nguyen@Sun.COM 		return (1);
656*8823STruong.Q.Nguyen@Sun.COM 	}
657*8823STruong.Q.Nguyen@Sun.COM 
658*8823STruong.Q.Nguyen@Sun.COM 	inst = scf_instance_create(h);
659*8823STruong.Q.Nguyen@Sun.COM 	snap = scf_snapshot_create(h);
660*8823STruong.Q.Nguyen@Sun.COM 	scratch_pg = scf_pg_create(h);
661*8823STruong.Q.Nguyen@Sun.COM 	scratch_prop = scf_property_create(h);
662*8823STruong.Q.Nguyen@Sun.COM 	scratch_v = scf_value_create(h);
663*8823STruong.Q.Nguyen@Sun.COM 
664*8823STruong.Q.Nguyen@Sun.COM 	if (inst == NULL || snap == NULL || scratch_pg == NULL ||
665*8823STruong.Q.Nguyen@Sun.COM 	    scratch_prop == NULL || scratch_v == NULL) {
666*8823STruong.Q.Nguyen@Sun.COM 		syslog(LOG_ERR | LOG_DAEMON, "Initialization failed: %s\n",
667*8823STruong.Q.Nguyen@Sun.COM 		    scf_strerror(scf_error()));
668*8823STruong.Q.Nguyen@Sun.COM 		return (1);
669*8823STruong.Q.Nguyen@Sun.COM 	}
670*8823STruong.Q.Nguyen@Sun.COM 
671*8823STruong.Q.Nguyen@Sun.COM 	return (repository_event_wait());
672*8823STruong.Q.Nguyen@Sun.COM }
673