xref: /illumos-gate/usr/src/cmd/fs.d/nfs/svc/nfs-server (revision 0dfe541e)
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#
24# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
25# Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
26# Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
27#
28
29# Start/stop processes required for server NFS
30
31. /lib/svc/share/smf_include.sh
32. /lib/svc/share/ipf_include.sh
33zone=`smf_zonename`
34
35#
36# Handling a corner case here. If we were in offline state due to an
37# unsatisfied dependency, the ipf_method process wouldn't have generated
38# the ipfilter configuration. When we transition to online because the
39# dependency is satisfied, the start method will have to generate the
40# ipfilter configuration. To avoid all possible deadlock scenarios,
41# we restart ipfilter which will regenerate the ipfilter configuration
42# for the entire system.
43#
44# The ipf_method process signals that it didn't generate ipf rules by
45# removing the service's ipf file. Thus we only restart network/ipfilter
46# when the file is missing.
47#
48configure_ipfilter()
49{
50	ipfile=`fmri_to_file $SMF_FMRI $IPF_SUFFIX`
51	ip6file=`fmri_to_file $SMF_FMRI $IPF6_SUFFIX`
52	[ -f "$ipfile" -a -f "$ip6file" ] && return 0
53
54        #
55	# Nothing to do if:
56        # - ipfilter isn't online
57	# - global policy is 'custom'
58	# - service's policy is 'use_global'
59        #
60        service_check_state $IPF_FMRI $SMF_ONLINE || return 0
61        [ "`get_global_def_policy`" = "custom" ] && return 0
62	[ "`get_policy $SMF_FMRI`" = "use_global" ] && return 0
63
64	svcadm restart $IPF_FMRI
65}
66
67case "$1" in
68'start')
69	# Share all file systems enabled for sharing. sharemgr understands
70	# regular shares and ZFS shares and will handle both. Technically,
71	# the shares would have been started long before getting here since
72	# nfsd has a dependency on them.
73
74	# restart stopped shares from the repository
75	/usr/sbin/sharemgr start -P nfs -a
76
77	# Options for nfsd are now set in SMF
78
79	/usr/lib/nfs/mountd
80	rc=$?
81	if [ $rc != 0 ]; then
82		/usr/sbin/svcadm mark -t maintenance svc:/network/nfs/server
83		echo "$0: mountd failed with $rc"
84		sleep 5 &
85		exit $SMF_EXIT_ERR_FATAL
86	fi
87
88	/usr/lib/nfs/nfsd
89	rc=$?
90	if [ $rc != 0 ]; then
91		/usr/sbin/svcadm mark -t maintenance svc:/network/nfs/server
92		echo "$0: nfsd failed with $rc"
93		sleep 5 &
94		exit $SMF_EXIT_ERR_FATAL
95	fi
96
97	configure_ipfilter
98	;;
99
100'refresh')
101	/usr/sbin/sharemgr start -P nfs -a
102	;;
103
104'stop')
105	/usr/bin/pkill -x -u 0,1 -z $zone '(nfsd|mountd)'
106
107	# Unshare all shared file systems using NFS
108
109	/usr/sbin/sharemgr stop -P nfs -a
110
111	# Kill any processes left in service contract
112	smf_kill_contract $2 TERM 1
113	[ $? -ne 0 ] && exit 1
114	;;
115
116'ipfilter')
117	#
118	# NFS related services are RPC. nfs/server has nfsd which has
119	# well-defined port number but mountd is an RPC daemon.
120	#
121	# Essentially, we generate rules for the following "services"
122	#  - nfs/server which has nfsd and mountd
123	#  - nfs/rquota
124	#
125	# The following services are enabled for both nfs client and
126	# server, if nfs/client is enabled we'll treat them as client
127	# services and simply allow incoming traffic.
128	#  - nfs/status
129	#  - nfs/nlockmgr
130	#  - nfs/cbd
131	#
132	NFS_FMRI="svc:/network/nfs/server:default"
133	NFSCLI_FMRI="svc:/network/nfs/client:default"
134	RQUOTA_FMRI="svc:/network/nfs/rquota:default"
135	FMRI=$2
136
137	file=`fmri_to_file $FMRI $IPF_SUFFIX`
138	file6=`fmri_to_file $FMRI $IPF6_SUFFIX`
139	echo "# $FMRI" >$file
140	echo "# $FMRI" >$file6
141	policy=`get_policy $NFS_FMRI`
142
143	#
144	# nfs/server configuration is processed in the start method.
145	#
146	if [ "$FMRI" = "$NFS_FMRI" ]; then
147		service_check_state $FMRI $SMF_ONLINE
148		if [ $? -ne 0 ]; then
149			rm  $file
150			exit $SMF_EXIT_OK
151		fi
152
153		nfs_name=`svcprop -p $FW_CONTEXT_PG/name $FMRI 2>/dev/null`
154		tport=`$SERVINFO -p -t -s $nfs_name 2>/dev/null`
155		if [ -n "$tport" ]; then
156			generate_rules $FMRI $policy "tcp" $tport $file
157		fi
158
159		tport6=`$SERVINFO -p -t6 -s $nfs_name 2>/dev/null`
160		if [ -n "$tport6" ]; then
161			generate_rules $FMRI $policy "tcp" $tport6 $file6 _6
162		fi
163
164		uport=`$SERVINFO -p -u -s $nfs_name 2>/dev/null`
165		if [ -n "$uport" ]; then
166			generate_rules $FMRI $policy "udp" $uport $file
167		fi
168
169		uport6=`$SERVINFO -p -u6 -s $nfs_name 2>/dev/null`
170		if [ -n "$uport6" ]; then
171			generate_rules $FMRI $policy "udp" $uport6 $file6 _6
172		fi
173
174		# mountd IPv6 ports are also reachable through IPv4, so include
175		# them when generating IPv4 rules.
176		tports=`$SERVINFO -R -p -t -s "mountd" 2>/dev/null`
177		tports6=`$SERVINFO -R -p -t6 -s "mountd" 2>/dev/null`
178		if [ -n "$tports" -o -n "$tports6" ]; then
179			tports=`unique_ports $tports $tports6`
180			for tport in $tports; do
181				generate_rules $FMRI $policy "tcp" \
182				    $tport $file
183			done
184		fi
185
186		if [ -n "$tports6" ]; then
187			for tport6 in $tports6; do
188				generate_rules $FMRI $policy "tcp" \
189				    $tport6 $file6 _6
190			done
191		fi
192
193		uports=`$SERVINFO -R -p -u -s "mountd" 2>/dev/null`
194		uports6=`$SERVINFO -R -p -u6 -s "mountd" 2>/dev/null`
195		if [ -n "$uports" -o -n "$uports6" ]; then
196			uports=`unique_ports $uports $uports6`
197			for uport in $uports; do
198				generate_rules $FMRI $policy "udp" \
199				    $uport $file
200			done
201		fi
202
203		if [ -n "$uports6" ]; then
204			for uport6 in $uports6; do
205				generate_rules $FMRI $policy "udp" \
206				    $uport6 $file6 _6
207			done
208		fi
209
210	elif [ "$FMRI" = "$RQUOTA_FMRI" ]; then
211		iana_name=`svcprop -p inetd/name $FMRI`
212
213		# rquota IPv6 ports are also reachable through IPv4, so include
214		# them when generating IPv4 rules.
215		tports=`$SERVINFO -R -p -t -s $iana_name 2>/dev/null`
216		tports6=`$SERVINFO -R -p -t6 -s $iana_name 2>/dev/null`
217		if [ -n "$tports" -o -n "$tports6" ]; then
218			tports=`unique_ports $tports $tports6`
219			for tport in $tports; do
220				generate_rules $NFS_FMRI $policy "tcp" \
221				    $tport $file
222			done
223		fi
224
225		if [ -n "$tports6" ]; then
226			for tport6 in $tports6; do
227				generate_rules $NFS_FMRI $policy "tcp" \
228				    $tport6 $file6 _6
229			done
230		fi
231
232		uports=`$SERVINFO -R -p -u -s $iana_name 2>/dev/null`
233		uports6=`$SERVINFO -R -p -u6 -s $iana_name 2>/dev/null`
234		if [ -n "$uports" -o -n "$uports6" ]; then
235			uports=`unique_ports $uports $uports6`
236			for uport in $uports; do
237				generate_rules $NFS_FMRI $policy "udp" \
238				    $uport $file
239			done
240		fi
241
242		if [ -n "$uports6" ]; then
243			for uport6 in $uports6; do
244				generate_rules $NFS_FMRI $policy "udp" \
245				    $uport6 $file6 _6
246			done
247		fi
248	else
249		#
250		# Handle the client services here
251		#
252		if service_check_state $NFSCLI_FMRI $SMF_ONLINE; then
253			policy=none
254			ip=any
255		fi
256
257		restarter=`svcprop -p general/restarter $FMRI 2>/dev/null`
258		if [ "$restarter" = "$INETDFMRI" ]; then
259			iana_name=`svcprop -p inetd/name $FMRI`
260			isrpc=`svcprop -p inetd/isrpc $FMRI`
261		else
262			iana_name=`svcprop -p $FW_CONTEXT_PG/name $FMRI`
263			isrpc=`svcprop -p $FW_CONTEXT_PG/isrpc $FMRI`
264		fi
265
266		if [ "$isrpc" = "true" ]; then
267			tports=`$SERVINFO -R -p -t -s $iana_name 2>/dev/null`
268			tports6=`$SERVINFO -R -p -t6 -s $iana_name 2>/dev/null`
269			uports=`$SERVINFO -R -p -u -s $iana_name 2>/dev/null`
270			uports6=`$SERVINFO -R -p -u6 -s $iana_name 2>/dev/null`
271		else
272			tports=`$SERVINFO -p -t -s $iana_name 2>/dev/null`
273			tports6=`$SERVINFO -p -t6 -s $iana_name 2>/dev/null`
274			uports=`$SERVINFO -p -u -s $iana_name 2>/dev/null`
275			uports6=`$SERVINFO -p -u6 -s $iana_name 2>/dev/null`
276		fi
277
278		# IPv6 ports are also reachable through IPv4, so include
279		# them when generating IPv4 rules.
280		if [ -n "$tports" -o -n "$tports6" ]; then
281			tports=`unique_ports $tports $tports6`
282			for tport in $tports; do
283				generate_rules $FMRI $policy "tcp" $tport $file
284			done
285		fi
286
287		if [ -n "$tports6" ]; then
288			for tport6 in $tports6; do
289				generate_rules $FMRI $policy "tcp" $tport6 $file6 _6
290			done
291		fi
292
293		if [ -n "$uports" -o -n "$uports6" ]; then
294			uports=`unique_ports $uports $uports6`
295			for uport in $uports; do
296				generate_rules $FMRI $policy "udp" $uport $file
297			done
298		fi
299
300		if [ -n "$uports6" ]; then
301			for uport6 in $uports6; do
302				generate_rules $FMRI $policy "udp" $uport6 $file6 _6
303			done
304		fi
305	fi
306
307	;;
308
309*)
310	echo "Usage: $0 { start | stop | refresh }"
311	exit 1
312	;;
313esac
314exit $SMF_EXIT_OK
315