xref: /illumos-gate/usr/src/cmd/svc/shell/ipf_include.sh (revision 5f8171005a0c33f3c67f7da52d41c2362c3fd891)
1#!/sbin/sh
2#
3# CDDL HEADER START
4#
5# The contents of this file are subject to the terms of the
6# Common Development and Distribution License (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22#
23# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26
27ETC_IPF_DIR=/etc/ipf
28IP6FILCONF=$ETC_IPF_DIR/ipf6.conf
29IPNATCONF=$ETC_IPF_DIR/ipnat.conf
30IPPOOLCONF=$ETC_IPF_DIR/ippool.conf
31VAR_IPF_DIR=/var/run/ipf
32IPFILCONF=$VAR_IPF_DIR/ipf.conf
33IPFILOVRCONF=$VAR_IPF_DIR/ipf_ovr.conf
34IPF_LOCK=/var/run/ipflock
35CONF_FILES=""
36NAT_FILES=""
37IPF_SUFFIX=".ipf"
38NAT_SUFFIX=".nat"
39
40# version for configuration upgrades
41CURRENT_VERSION=1
42
43IPF_FMRI="svc:/network/ipfilter:default"
44INETDFMRI="svc:/network/inetd:default"
45RPCBINDFMRI="svc:/network/rpc/bind:default"
46
47SMF_ONLINE="online"
48SMF_MAINT="maintenance"
49SMF_NONE="none"
50
51FW_CONTEXT_PG="firewall_context"
52METHOD_PROP="ipf_method"
53
54FW_CONFIG_PG="firewall_config"
55POLICY_PROP="policy"
56APPLY2_PROP="apply_to"
57EXCEPTIONS_PROP="exceptions"
58
59FW_CONFIG_DEF_PG="firewall_config_default"
60FW_CONFIG_OVR_PG="firewall_config_override"
61CUSTOM_FILE_PROP="custom_policy_file"
62OPEN_PORTS_PROP="open_ports"
63
64PREFIX_HOST="host:"
65PREFIX_NET="network:"
66PREFIX_POOL="pool:"
67PREFIX_IF="if:"
68
69SERVINFO=/usr/lib/servinfo
70
71#
72# Given a service, gets its config pg name
73#
74get_config_pg()
75{
76	if [ "$1" = "$IPF_FMRI" ]; then
77		echo "$FW_CONFIG_DEF_PG"
78	else
79		echo "$FW_CONFIG_PG"
80	fi
81	return 0
82}
83
84#
85# Given a service, gets its firewall policy
86#
87get_policy()
88{
89	config_pg=`get_config_pg $1`
90	svcprop -p $config_pg/${POLICY_PROP} $1 2>/dev/null
91}
92
93get_global_def_policy()
94{
95	svcprop -p ${FW_CONFIG_DEF_PG}/${POLICY_PROP} $IPF_FMRI 2>/dev/null
96}
97
98#
99# Given a service, gets its firewall policy
100#
101get_exceptions()
102{
103	config_pg=`get_config_pg $1`
104	svcprop -p $config_pg/${EXCEPTIONS_PROP} $1 2>/dev/null
105}
106
107#
108# Given a service, gets its firewall policy
109#
110get_apply2_list()
111{
112	config_pg=`get_config_pg $1`
113	svcprop -p $config_pg/${APPLY2_PROP} $1 2>/dev/null
114}
115
116check_ipf_dir()
117{
118	[ -d $VAR_IPF_DIR ] && return 0
119	mkdir $VAR_IPF_DIR >/dev/null 2>&1 || return 1
120}
121
122#
123# fmri_to_file fmri suffix
124#
125fmri_to_file()
126{
127	check_ipf_dir || return 1
128	fprefix="${VAR_IPF_DIR}/`echo $1 | tr -s '/:' '__'`"
129	echo "${fprefix}${2}"
130}
131
132#
133# Return service's enabled property
134#
135service_is_enabled()
136{
137	#
138	# Temporary enabled state overrides the persistent state
139	# so check it first.
140	#
141	enabled_ovr=`svcprop -c -p general_ovr/enabled $1 2>/dev/null`
142	if [ -n "$enabled_ovr" ]; then
143		[ "$enabled_ovr" = "true" ] && return 0 || return 1
144	fi
145
146	enabled=`svcprop -c -p general/enabled $1 2>/dev/null`
147	[ -n "$enabled" -a "$enabled" = "true" ] && return 0 || return 1
148}
149
150#
151# Return whether service is desired state
152#
153# Args: fmri state
154# Return:
155#  0 - desired state is service's current state
156#  1 - desired state is not service's current state
157#
158service_check_state()
159{
160	#
161	# Make sure we're done with ongoing state transition
162	#
163	while [ "`svcprop -p restarter/next_state $1`" != "$SMF_NONE" ]; do
164		sleep 1
165	done
166
167	[ "`svcprop -p restarter/state $1`" = "$2" ] && return 0 || return 1
168}
169
170#
171# Deny/Allow list stores values in the form "host:addr", "network:addr/netmask",
172# "pool:number", and "if:interface". This function returns the
173# IP(addr or addr/netmask) value or a pool number.
174#
175get_IP()
176{
177	value_is_interface $1 && return 1
178	echo "$1" | sed -n -e 's,^pool:\(.*\),pool/\1,p' \
179	    -e 's,^host:\(.*\),\1,p' \
180	    -e 's,^network:\(.*\),\1,p'
181}
182
183get_interface()
184{
185	value_is_interface $1 || return 1
186	scratch=`echo "$1" | sed -e 's/^if://'`
187
188	ifconfig $scratch >/dev/null 2>&1 || return 1
189	echo $scratch | sed -e 's/:.*//'
190}
191
192#
193#
194#
195value_is_interface()
196{
197	[ -z "$1" ] && return 1
198	echo $1 | grep "^if:" >/dev/null 2>&1
199}
200
201#
202# Remove rules in given file from active list without restarting ipfilter
203#
204remove_rules()
205{
206	[ -f "$1" ] && ipf -r -f $1 >/dev/null 2>&1
207}
208
209remove_nat_rules()
210{
211	[ -f "$1" ] && ipnat -r -f $1 >/dev/null 2>&1
212}
213
214check_ipf_syntax()
215{
216	ipf -n -f $1 >/dev/null 2>&1
217}
218
219check_nat_syntax()
220{
221	ipnat -n -f $1 >/dev/null 2>&1
222}
223
224file_get_ports()
225{
226	ipf -n -v -f $1 2>/dev/null | sed -n -e \
227	    's/.*to.* port = \([a-z0-9]*\).*/\1/p' | uniq | \
228	    awk '{if (length($0) > 1) {printf("%s ", $1)}}'
229}
230
231get_active_ports()
232{
233	ipfstat -io 2>/dev/null | sed -n -e \
234	    's/.*to.* port = \([a-z0-9]*\).*/\1/p' | uniq | \
235	    awk '{if (length($0) > 1) {printf("%s ",$1)}}'
236}
237
238#
239# Given two list of ports, return failure if there's a duplicate.
240#
241sets_check_duplicate()
242{
243	#
244	# If either list is empty, there isn't any conflict.
245	#
246	[ -z "$1" -o -z "$2" ] && return 0
247
248	for p in $1; do
249		for ap in $2; do
250			[ "$p" = "$ap" ] && return 1
251		done
252	done
253
254	return 0
255}
256
257#
258# Given a file containing ipf rules, check the syntax and verify
259# the rules don't conflict, use same port number, with active
260# rules (ipfstat -io output).
261#
262update_check_ipf_rules()
263{
264	check_ipf_syntax $1 || return 1
265
266	lports=`file_get_ports $1`
267	lactive_ports=`get_active_ports`
268
269	sets_check_duplicate "$lports" "$lactive_ports" || return 1
270}
271
272server_port_list=""
273
274#
275# Given a file containing ipf rules, check the syntax and verify
276# the rules don't conflict with already processed services.
277#
278# The list of processed services' ports are maintained in the global
279# variable 'server_port_list'.
280#
281check_ipf_rules()
282{
283	check_ipf_syntax $1 || return 1
284
285	lports=`file_get_ports $1`
286	sets_check_duplicate "$lports" "$server_port_list" || return 1
287	server_port_list="$server_port_list $lports"
288	return 0
289}
290
291prepend_new_rules()
292{
293	check_ipf_syntax $1 && tail -r $1 | sed -e 's/^[a-z]/@0 &/' | \
294	    ipf -f - >/dev/null 2>&1
295}
296
297append_new_rules()
298{
299	check_ipf_syntax $1 && ipf -f $1 >/dev/null 2>&1
300}
301
302append_new_nat_rules()
303{
304	check_nat_syntax $1 && ipnat -f $1 >/dev/null 2>&1
305}
306
307#
308# get port information from string of the form "proto:{port | port-port}"
309#
310tuple_get_port()
311{
312	port_str=`echo "$1" | sed -e 's/ //g; s/.*://' 2>/dev/null`
313	[ -z "$port_str" ] && return 1
314
315	echo $port_str | grep "-" >/dev/null
316	if  [ $? -eq  0 ]; then
317		echo $port_str | grep '^[0-9]\{1,5\}-[0-9]\{1,5\}$' >/dev/null || \
318		    return 1
319		ports=`echo $port_str | ( IFS=- read a b ; \
320		    [ $a \-le $b ] && echo $a $b || echo $b $a )`
321
322		for p in $ports; do
323			[ $p -gt 65535 ] && return 1
324		done
325		echo "$ports"
326	else
327		#
328		# port_str is a single port, verify and return it.
329		#
330		echo "$port_str" | grep '^[0-9]\{1,5\}$' >/dev/null || return 1
331		[ $port_str -gt 65535 ] && return 1
332		echo "$port_str"
333	fi
334}
335
336#
337# get proto info from string of the form "{tcp | udp}:port"
338#
339tuple_get_proto()
340{
341	proto=`echo "$1" | sed -e 's/ //g; s/:.*//' 2>/dev/null`
342	[ -z "$proto" ] && return 0
343
344	[ "$proto" = "tcp" -o "$proto" = "udp" ] && echo $proto || return 1
345	return 0
346}
347
348ipf_get_lock()
349{
350	newpid=$$
351
352	if [ -f "$IPF_LOCK/pid" ]; then
353		curpid=`cat $IPF_LOCK/pid 2>/dev/null`
354		[ "$curpid" = "$newpid" ] && return 0
355
356		#
357		# Clear lock if the owning process is no longer around.
358		#
359		ps -p $curpid >/dev/null 2>&1 || rm -r $IPF_LOCK >/dev/null 2>&1
360	fi
361
362	#
363	# Grab the lock
364	#
365	while :; do
366		mkdir $IPF_LOCK 2>/dev/null && break;
367		sleep 1
368	done
369	echo $newpid > $IPF_LOCK/pid
370}
371
372#
373# Remove lock if it's ours
374#
375ipf_remove_lock()
376{
377	if [ -f "$IPF_LOCK/pid" ]; then
378		[ "`cat $IPF_LOCK/pid`" = "$$" ] && rm -r $IPF_LOCK
379	fi
380	return 0
381}
382
383#
384# Make IPFILCONF, /var/tmp/ipf/ipf.conf, a symlink to the input file argument.
385#
386custom_set_symlink()
387{
388	#
389	# Nothing to do if the input file doesn't exist.
390	#
391	[ ! -f "$1" ] && return 0
392
393	check_ipf_dir || return 1
394
395	rm $IPFILCONF >/dev/null 2>&1
396	ln -s $1 $IPFILCONF >/dev/null 2>&1
397}
398
399#
400# New file replaces original file if they have different content
401#
402replace_file()
403{
404	orig=$1
405	new=$2
406
407	#
408	# IPFILCONF may be a symlink, remove it if that's the case
409	#
410	if [ -L "$orig" ]; then
411		rm $orig
412		touch $orig
413	fi
414
415	check_ipf_dir || return 1
416	mv $new $orig && return 0 || return 1
417}
418
419#
420# Given a service, gets the following details for ipf rule:
421# - policy
422# - protocol
423# - port(IANA port obtained by running servinfo)
424#
425process_server_svc()
426{
427	service=$1
428	ip="any"
429        policy=`get_policy ${service}`
430
431	#
432	# Empties service's rules file so callers won't use existing rule if
433	# we fail here.
434	#
435	file=`fmri_to_file $service $IPF_SUFFIX`
436	[ -z "$file" ] && return 1
437	echo "# $service" >${file}
438
439	#
440	# Nothing to do if policy is "use_global"
441	#
442	[ "$policy" = "use_global" ] && return 0
443
444	restarter=`svcprop -p general/restarter $service 2>/dev/null`
445	if [ "$restarter" = "$INETDFMRI" ]; then
446		iana_name=`svcprop -p inetd/name $service 2>/dev/null`
447		isrpc=`svcprop -p inetd/isrpc $service 2>/dev/null`
448	else
449		iana_name=`svcprop -p $FW_CONTEXT_PG/name $service 2>/dev/null`
450		isrpc=`svcprop -p $FW_CONTEXT_PG/isrpc $service 2>/dev/null`
451	fi
452
453	#
454	# Bail if iana_name isn't defined. Services with static rules
455	# like nis/client don't need to generate rules using
456	# iana name and protocol information.
457	#
458	[ -z "$iana_name" ] && return 1
459
460	#
461	# RPC services
462	#
463	if [ "$isrpc" = "true" ]; then
464		tports=`$SERVINFO -R -p -t -s $iana_name 2>/dev/null`
465		if [ -n "$tports" ]; then
466			for tport in $tports; do
467				generate_rules $service $policy "tcp" \
468				    $ip $tport $file
469			done
470		fi
471
472		uports=`$SERVINFO -R -p -u -s $iana_name 2>/dev/null`
473		if [ -n "$uports" ]; then
474			for uport in $uports; do
475				generate_rules $service $policy "udp" \
476				    $ip $uport $file
477			done
478		fi
479
480		return 0
481	fi
482
483	#
484	# Get the IANA port and supported protocols(tcp and udp)
485	# No support for IPv6 at this point.
486	#
487	tport=`$SERVINFO -p -t -s $iana_name 2>&1`
488	if [ $? -eq 0 -a -n "$tport" ]; then
489		generate_rules $service $policy "tcp" $ip $tport $file
490	fi
491
492	uport=`$SERVINFO -p -u -s $iana_name 2>&1`
493	if [ $? -eq 0 -a -n "$uport" ]; then
494		generate_rules $service $policy "udp" $ip $uport $file
495	fi
496
497	return 0
498}
499
500#
501# Given a service's name, policy, protocol and port, generate ipf rules
502# - list of host/network/interface to apply policy
503#
504# A 'use_global' policy inherits the system-wided Global Default policy
505# from network/ipfilter. For {deny | allow} policies, the rules are
506# ordered as:
507#
508# - make exceptions to policy for those in "exceptions" list
509# - apply policy to those specified in "apply_to" list
510# - policy rule
511#
512generate_rules()
513{
514	service=$1
515	mypolicy=$2
516	proto=$3
517	ip=$4
518	port=$5
519	out=$6
520
521	#
522	# Default mode is to inherit from global's policy
523	#
524	[ "$mypolicy" = "use_global" ] && return 0
525
526	tcp_opts=""
527	[ "$proto" = "tcp" ] && tcp_opts="flags S keep state keep frags"
528
529	#
530	# Allow all if policy is 'none'
531	#
532	if [ "$mypolicy" = "none" ]; then
533		echo "pass in log quick proto ${proto} from any to ${ip}" \
534		    "port = ${port} ${tcp_opts}" >>${out}
535		return 0
536	fi
537
538	#
539	# For now, let's concern only with incoming traffic.
540	#
541	[ "$mypolicy" = "deny" ] && { ecmd="pass"; acmd="block"; }
542	[ "$mypolicy" = "allow" ] && { ecmd="block"; acmd="pass"; }
543
544	for name in `get_exceptions $service`; do
545		[ -z "$name" -o "$name" = '""' ] && continue
546
547		ifc=`get_interface $name`
548		if [ $? -eq 0 -a -n "$ifc" ]; then
549			echo "${ecmd} in log quick on ${ifc} from any to" \
550			    "${ip} port = ${port}" >>${out}
551			continue
552		fi
553
554		addr=`get_IP ${name}`
555		if [ $? -eq 0 -a -n "$addr" ]; then
556			echo "${ecmd} in log quick proto ${proto} from ${addr}" \
557			    "to ${ip} port = ${port} ${tcp_opts}" >>${out}
558		fi
559	done
560
561	for name in `get_apply2_list $service`; do
562		[ -z "$name" -o "$name" = '""' ] && continue
563
564		ifc=`get_interface $name`
565		if [ $? -eq 0 -a -n "$ifc" ]; then
566			echo "${acmd} in log quick on ${ifc} from any to" \
567			    "${ip} port = ${port}" >>${out}
568			continue
569		fi
570
571		addr=`get_IP ${name}`
572		if [ $? -eq 0 -a -n "$addr" ]; then
573			echo "${acmd} in log quick proto ${proto} from ${addr}" \
574			    "to ${ip} port = ${port} ${tcp_opts}" >>${out}
575		fi
576	done
577
578	echo "${ecmd} in log quick proto ${proto} from any to ${ip}" \
579	    "port = ${port} ${tcp_opts}" >>${out}
580
581	return 0
582}
583
584#
585# Service has either IANA ports and proto or its own firewall method to
586# generate the rules.
587#
588# - if service has a custom method, use it to populate its rules
589# - if service has a firewall_config pg, use process_server_svc
590#
591# Argument - fmri
592#
593process_service()
594{
595	#
596	# Don't process network/ipfilter
597	#
598	[ "$1" = "$IPF_FMRI" ] && return 0
599
600	service_check_state $1 $SMF_MAINT && return 1
601
602	method=`svcprop -p $FW_CONTEXT_PG/$METHOD_PROP $1 2>/dev/null | \
603	    sed 's/\\\//g'`
604	if [ -n "$method" -a "$method" != '""' ]; then
605		( exec $method $1 >/dev/null )
606	else
607		svcprop -p $FW_CONFIG_PG $1 >/dev/null 2>&1 || return 1
608		process_server_svc $1 || return 1
609	fi
610	return 0
611}
612
613#
614# Generate rules for protocol/port defined in firewall_config_default/open_ports
615# property. These are non-service programs whose network resource info are
616# defined as "{tcp | upd}:{PORT | PORT-PORT}". Essentially, these programs need
617# some specific local ports to be opened. For example, BitTorrent clients need to
618# have 6881-6889 opened.
619#
620process_nonsvc_progs()
621{
622	out=$1
623	echo "# Non-service programs rules" >>${out}
624	progs=`svcprop -p ${FW_CONFIG_DEF_PG}/${OPEN_PORTS_PROP} \
625	    $SMF_FMRI 2>/dev/null`
626
627	for prog in $progs; do
628		[ -z "$prog" -o "$prog" = '""' ] && continue
629
630		port=`tuple_get_port $prog`
631		[ $? -eq 1 -o -z "$port" ] && continue
632
633		proto=`tuple_get_proto $prog`
634		[ $? -eq 1 ] && continue
635
636		set -- $port
637		if  [ $# -gt 1 ]; then
638			if [ -z "$proto" ]; then
639				echo "pass in log quick from any to any" \
640				    "port ${1} >< ${2}" >>${out}
641			else
642				echo "pass in log quick proto ${proto} from any" \
643				    "to any port ${1} >< ${2}" >>${out}
644			fi
645		else
646			if [ -z "$proto" ]; then
647				echo "pass in log quick from any to any" \
648				    "port = ${1}" >>${out}
649			else
650				echo "pass in log quick proto ${proto} from any" \
651				    "to any port = ${1}" >>${out}
652			fi
653		fi
654	done
655
656	return 0
657}
658
659#
660# Generate a new /etc/ipf/ipf.conf. If firewall policy is 'none',
661# ipf.conf is empty .
662#
663create_global_rules()
664{
665	policy=`get_global_def_policy`
666
667	if [ "$policy" = "custom" ]; then
668		file=`svcprop -p ${FW_CONFIG_DEF_PG}/${CUSTOM_FILE_PROP} $SMF_FMRI`
669
670		[ -n "$file" ] && custom_set_symlink $file
671		return 0
672	fi
673
674	TEMP=`mktemp /var/run/ipf.conf.pid$$.XXXXXX`
675	process_nonsvc_progs $TEMP
676
677	echo "# Global Default rules" >>${TEMP}
678	if [ "$policy" != "none" ]; then
679		echo "pass out log quick all keep state" >>${TEMP}
680	fi
681
682	case "$policy" in
683	'none')
684		# No rules
685		replace_file ${IPFILCONF} ${TEMP}
686		return $?
687		;;
688
689	'deny')
690		ecmd="pass"
691		acmd="block"
692		;;
693
694	'allow')
695		ecmd="block"
696		acmd="pass"
697		;;
698	*)
699		return 1;
700		;;
701	esac
702
703	for name in `get_exceptions $SMF_FMRI`; do
704		[ -z "$name" -o "$name" = '""' ] && continue
705
706		ifc=`get_interface $name`
707		if [ $? -eq 0 -a -n "$ifc" ]; then
708			echo "${ecmd} in log quick on ${ifc} all" >>${TEMP}
709			continue
710		fi
711
712		addr=`get_IP ${name}`
713		if [ $? -eq 0 -a -n "$addr" ]; then
714			echo "${ecmd} in log quick from ${addr} to any" >>${TEMP}
715		fi
716
717	done
718
719	for name in `get_apply2_list $SMF_FMRI`; do
720		[ -z "$name" -o "$name" = '""' ] && continue
721
722		ifc=`get_interface $name`
723		if [ $? -eq 0 -a -n "$ifc" ]; then
724			echo "${acmd} in log quick on ${ifc} all" >>${TEMP}
725			continue
726		fi
727
728		addr=`get_IP ${name}`
729		if [ $? -eq 0 -a -n "$addr" ]; then
730			echo "${acmd} in log quick from ${addr} to any" >>${TEMP}
731		fi
732	done
733
734	if [ "$policy" = "allow" ]; then
735		#
736		# Allow DHCP traffic if running as a DHCP client
737		#
738		/sbin/netstrategy | grep dhcp >/dev/null 2>&1
739		if [ $? -eq 0 ]; then
740			echo "pass out log quick from any port = 68" \
741			    "keep state" >>${TEMP}
742			echo "pass out log quick from any port = 546" \
743			    "keep state" >>${TEMP}
744			echo "pass in log quick from any to any port = 68" >>${TEMP}
745			echo "pass in log quick from any to any port = 546" >>${TEMP}
746		fi
747		echo "block in log all" >>${TEMP}
748	fi
749
750	replace_file ${IPFILCONF} ${TEMP}
751	return $?
752}
753
754#
755# Generate a new /etc/ipf/ipf_ovr.conf, the override system-wide policy. It's
756# a simplified policy that doesn't support 'exceptions' entities.
757#
758# If firewall policy is "none", no rules are generated.
759#
760# Note that "pass" rules don't have "quick" as we don't want
761# them to override services' block rules.
762#
763create_global_ovr_rules()
764{
765	#
766	# Simply empty override file if global policy is 'custom'
767	#
768	if [ "`get_global_def_policy`" = "custom" ]; then
769		echo "# 'custom' global policy" >$IPFILOVRCONF
770		return 0
771	fi
772
773	#
774	# Get and process override policy
775	#
776	ovr_policy=`svcprop -p ${FW_CONFIG_OVR_PG}/${POLICY_PROP} $IPF_FMRI`
777	if [ "$ovr_policy" = "none" ]; then
778		echo "# global override policy is 'none'" >$IPFILOVRCONF
779		return 0
780	fi
781
782	TEMP=`mktemp /var/run/ipf_ovr.conf.pid$$.XXXXXX`
783	[ "$ovr_policy" = "deny" ] && acmd="block in log quick"
784	[ "$ovr_policy" = "allow" ] && acmd="pass in log"
785
786	apply2_list=`svcprop -p $FW_CONFIG_OVR_PG/$APPLY2_PROP $IPF_FMRI`
787	for name in $apply2_list; do
788		[ -z "$name" -o "$name" = '""' ] && continue
789
790		ifc=`get_interface $name`
791		if [ $? -eq 0 -a -n "$ifc" ]; then
792			echo "${acmd} on ${ifc} all" >>${TEMP}
793			continue
794		fi
795
796		addr=`get_IP ${name}`
797		if [ $? -eq 0 -a -n "$addr" ]; then
798			echo "${acmd} from ${addr} to any" >>${TEMP}
799		fi
800	done
801
802	replace_file ${IPFILOVRCONF} ${TEMP}
803	return $?
804}
805
806#
807# Service is put into maintenance state due to its invalid firewall
808# definition and/or policy.
809#
810svc_mark_maintenance()
811{
812	svcadm mark maintenance $1 >/dev/null 2>&1
813
814	date=`date`
815	echo "[ $date ${0}: $1 has invalid ipf configuration. ]"
816	echo "[ $date ${0}: placing $1 in maintenance. ]"
817
818	#
819	# Move service's rule files to another location since
820	# they're most likely invalid.
821	#
822	ipfile=`fmri_to_file $1 $IPF_SUFFIX`
823	[ -f "$ipfile" ] && mv $ipfile "$ipfile.bak"
824
825	natfile=`fmri_to_file $1 $NAT_SUFFIX`
826	[ -f "$natfile" ] && mv $natfile "$natfile.bak"
827
828	return 0
829}
830
831svc_is_server()
832{
833	svcprop -p $FW_CONFIG_PG $1 >/dev/null 2>&1
834}
835
836#
837# Create rules for enabled firewalling and client services.
838# - obtain the list of enabled services and process them
839# - save the list of rules file for later use
840#
841create_services_rules()
842{
843	#
844	# Do nothing if global policy is 'custom'
845	#
846	global_policy=`get_global_def_policy`
847	[ "$global_policy" = "custom" ] && return 0
848
849	ipf_get_lock
850
851	#
852	# Get all enabled services
853	#
854	allsvcs=`svcprop -cf -p general/enabled -p general_ovr/enabled '*' \
855	    2>/dev/null | sed -n 's,^\(svc:.*\)/:properties/.* true$,\1,p' | sort -u`
856
857	#
858	# Process enabled services
859	#
860	for s in $allsvcs; do
861		service_is_enabled $s || continue
862		process_service $s || continue
863
864		ipfile=`fmri_to_file $s $IPF_SUFFIX`
865		if [ -n "$ipfile" -a -r "$ipfile" ]; then
866			check_ipf_syntax $ipfile
867			if [ $? -ne 0 ]; then
868				svc_mark_maintenance $s
869				continue
870			fi
871
872			svc_is_server $s
873			if [ $? -eq 0 ]; then
874				check_ipf_rules $ipfile
875				if [ $? -ne 0 ]; then
876					svc_mark_maintenance $s
877					continue
878				fi
879			fi
880			CONF_FILES="$CONF_FILES $ipfile"
881		fi
882
883		natfile=`fmri_to_file $s $NAT_SUFFIX`
884		if [ -n "$natfile" -a -r "$natfile" ]; then
885			check_nat_syntax $natfile
886			if [ $? -ne 0 ]; then
887				svc_mark_maintenance $s
888				continue
889			fi
890
891			NAT_FILES="$NAT_FILES $natfile"
892		fi
893	done
894
895	ipf_remove_lock
896	return 0
897}
898
899#
900# We update a services ipf ruleset in the following manners:
901# - service is disabled, tear down its rules.
902# - service is disable or refreshed(online), setup or update its rules.
903#
904service_update_rules()
905{
906	#
907	# If ipfilter isn't online or global policy is 'custom',
908	# nothing should be done.
909	#
910	service_check_state $SMF_FMRI $SMF_ONLINE || return 0
911	[ "`get_global_def_policy`" = "custom" ] && return 0
912
913	svc=$1
914
915	ipfile=`fmri_to_file $svc $IPF_SUFFIX`
916	[ -z "$ipfile" ] && return 0
917
918	remove_rules $ipfile
919
920	natfile=`fmri_to_file $svc $NAT_SUFFIX`
921	[ -n "$natfile" ] && remove_nat_rules $natfile
922
923	#
924	# Don't go further if service is disabled or in maintenance.
925	#
926	service_is_enabled $svc || return 0
927	service_check_state $1 $SMF_MAINT && return 0
928
929	process_service $svc || return 1
930	if [ -f "$ipfile" ]; then
931		check_ipf_syntax $ipfile
932		if [ $? -ne 0 ]; then
933			svc_mark_maintenance $svc
934			return 1
935		fi
936	fi
937
938	if [ -f "$natfile" ]; then
939		check_nat_syntax $natfile
940		if [ $? -ne 0 ]; then
941			svc_mark_maintenance $svc
942			return 1
943		fi
944	fi
945
946	if [ -f "$ipfile" ]; then
947		svc_is_server $svc
948		if [ $? -eq 0 ]; then
949			update_check_ipf_rules $ipfile
950			if [ $? -ne 0 ]; then
951				svc_mark_maintenance $svc
952				return 1
953			fi
954		fi
955
956		prepend_new_rules $ipfile
957
958		#
959		# reload Global Override rules to
960		# maintain correct ordering.
961		#
962		remove_rules $IPFILOVRCONF
963		prepend_new_rules $IPFILOVRCONF
964	fi
965
966	[ -f "$natfile" ] && append_new_nat_rules $natfile
967
968	return 0
969}
970
971#
972# Call the service_update_rules with appropriate svc fmri.
973#
974# This is called from '/lib/svc/method/ipfilter fw_update' whenever
975# a service is disabled/enabled/refreshed.
976#
977service_update()
978{
979	svc=$1
980	ret=0
981
982	ipf_get_lock
983	service_update_rules $svc || ret=1
984
985	ipf_remove_lock
986	return $ret
987}
988