xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/ftpconfig.sh (revision 11464:1d600a70eaf2)
1#!/usr/bin/ksh
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 2010 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26#
27# This script sets up anonymous FTP on the current host.
28#
29# Usage:
30#	ftpconfig [ftpdir]
31#	ftpconfig -d ftpdir
32#
33# ftpconfig without any arguments updates the files required by anonymous FTP
34# in an existing ftp users home directory.
35#
36# If ftpdir (which must be an absolute pathname) is supplied, ftpconfig
37# creates an ftp user account with a home directory of ftpdir, or updates
38# an existing ftp user account to have a home directory of ftpdir.
39#
40# If ftpdir already exists, the files it contains which are required by
41# anonymous FTP are updated, otherwise ftpdir is created containing the files
42# required by anonymous FTP.
43#
44# The -d (directory only) option just creates a new or updates an existing
45# ftpdir without creating or updating the ftp user account. This is useful
46# when creating guest FTP user accounts.
47#
48# Exit codes:	0 - success
49#		1 - usage
50#		2 - command failure
51#
52
53usage()
54{
55	fmt=`gettext "Usage: %s [ftpdir]\n       %s -d ftpdir"`
56	printf "$fmt\n" "$cmd" "$cmd" >&2
57	exit 1
58}
59
60verify_root()
61{
62	# Verify caller has a real user ID of 0.
63	set `id`
64	if [ "$1" != "uid=0(root)" ]
65	then
66		fmt=`gettext "%s: Error: Only root can run %s"`
67		printf "$fmt\n" "$cmd" "$cmd" >&2
68		exit 1
69	fi
70}
71
72# Make directory $1 under $home_dir with mode $2 and ownership $3.
73make_dir()
74{
75	# Make a special case of creating $home_dir itself
76	if [ -z "$1" ]
77	then
78		dir="$home_dir"
79	else
80		dir="$home_dir/$1"
81	fi
82	if [ ! -d "$dir" ]
83	then
84		mkdir "$dir" || exit 2
85	fi
86	chmod "$2" "$dir"
87	chown "$3" "$dir"
88}
89
90# Copy file $1 to under $home_dir with mode $2 and ownership $3.
91copy_file()
92{
93	if [ -f "$1" ]
94	then
95		file="$home_dir$1"
96		rm -f "$file"
97		cp "$1" "$file" || exit 2
98		chmod "$2" "$file"
99		chown "$3" "$file"
100	fi
101}
102
103add_user()
104{
105	pwent=`grep "^$username:" /etc/passwd`
106	if [ -z "$pwent" ]
107	then
108		# No existing ftp account.
109		if [ -z "$home_dir" ]
110		then
111			fmt=`gettext "%s: Error: No directory specified and no existing ftp account to update"`
112			printf "$fmt\n" "$cmd" >&2
113			exit 1
114		fi
115
116		# Create a new ftp account.
117		comment="Anonymous FTP"
118		fmt=`gettext "Creating user %s"`
119		printf "$fmt\n" "$username"
120		/usr/sbin/useradd -c "$comment" -d "$home_dir" -s "$login_shell" -g other "$username" || exit 2
121	else
122		# ftp account already exists.
123		if [ -z "$home_dir" ]
124		then
125			home_dir=`echo "$pwent" | cut -d: -f6`
126			if [ -z "$home_dir" ]
127			then
128				fmt=`gettext "%s: Error: Existing ftp account has no home directory"`
129				printf "$fmt\n" "$cmd" >&2
130				exit 2
131			fi
132		else
133			# Update an existing ftp account.
134			old_dir=`echo "$pwent" | cut -d: -f6`
135			if [ "$old_dir" != "$home_dir" ]
136			then
137				fmt=`gettext "Updating user %s"`
138				printf "$fmt\n" "$username"
139				/usr/sbin/usermod -d "$home_dir" "$username" || exit 2
140			fi
141		fi
142	fi
143}
144
145list_pam_session()
146{
147	# Produce a list of the PAM session management modules.
148	if [ -f /etc/pam.conf ]
149	then
150		awk '($1 == "ftp" || $1 == "other") && $2 == "session" {
151			if ($4 !~ /^\//) printf "/usr/lib/security/"
152			print $4
153		}' </etc/pam.conf | sed 's/$ISA\///'
154	fi
155}
156
157list_conv_cmds()
158{
159	# Produce a list of the commands specified in the conversions file.
160	if [ -f /etc/ftpd/ftpconversions ]
161	then
162		sed 's/#.*$//' /etc/ftpd/ftpconversions | cut -d: -f5 |
163			awk '$1 !~ /^$/ { print $1 }' | sort -u
164	fi
165}
166
167list_dyn_libs()
168{
169	# Produce a list of the required dynamic libraries.
170	for file in $* /usr/sbin/in.ftpd /usr/bin/ls `list_conv_cmds`
171	do
172		ldd "$file" 2>/dev/null | cut -d'>' -f2
173	done | sort -u
174}
175
176create_home_dir()
177{
178	if [ "$home_dir" = "/" -o "$home_dir" = "/usr" ]
179	then
180		fmt=`gettext "%s: Error: Installing FTP in %s is not permitted"`
181		printf "$fmt\n" "$cmd" "$home_dir" >&2
182		exit 1
183	fi
184
185	if [ ! -d "$home_dir" ]
186	then
187		if [ -e "$home_dir" ]
188		then
189			fmt=`gettext "%s: Error: %s already exists but is not a directory"`
190			printf "$fmt\n" "$cmd" "$home_dir" >&2
191			exit 2
192		else
193			fmt=`gettext "Creating directory %s"`
194			printf "$fmt\n" "$home_dir"
195			make_dir "" 755 root:sys
196		fi
197	fi
198}
199
200install_slash_etc()
201{
202	# Preserve an existing etc directory.
203	make_dir etc 111 root:sys
204	make_dir etc/ftpd 111 root:sys
205
206	# Create a stripped down password file.
207	rm -f "$home_dir/etc/passwd"
208	awk -F: '$1 ~ /^root$|^bin$|^sys$|^ftpadm$|^ftp$/ { print $1":x:"$3":"$4":::" }' </etc/passwd >"$home_dir/etc/passwd"
209	chmod 444 "$home_dir/etc/passwd"
210	chown root:sys "$home_dir/etc/passwd"
211
212	# Create a stripped down group file.
213	rm -f "$home_dir/etc/group"
214	awk -F: '$1 ~ /^root$|^other$|^bin$|^sys$|^ftpadm$/ { print $1"::"$3":" }' </etc/group >"$home_dir/etc/group"
215	chmod 444 "$home_dir/etc/group"
216	chown root:sys "$home_dir/etc/group"
217
218	# Copy in /etc/default/init, needed for timezone.
219	if [ -f /etc/default/init ]
220	then
221		make_dir etc/default 111 root:sys
222		copy_file /etc/default/init 444 root:sys
223	fi
224
225	# Copy in files used for hostname resolution
226	copy_file /etc/hosts 444 root:sys
227	copy_file /etc/resolv.conf 444 root:sys
228	make_dir etc/inet 111 root:sys
229	copy_file /etc/inet/ipnodes 444 root:sys
230}
231
232install_slash_usr()
233{
234	# Preserve an existing usr directory.
235	make_dir usr 111 root:sys
236	make_dir usr/bin 111 root:bin
237
238	if [ -h "$home_dir/bin" ]
239	then
240		rm -f "$home_dir/bin"
241	fi
242	if [ ! -e "$home_dir/bin" ]
243	then
244		ln -s ./usr/bin "$home_dir/bin" || exit 2
245		chown -h root:bin "$home_dir/bin"
246	fi
247
248	# Copy required dynamic libraries and PAM session management modules.
249	libs="/lib/nss_files.so.1 /lib/nss_dns.so.1 /lib/libresolv.so.2"
250	for lib in /lib/ld.so.1 $libs `list_dyn_libs $libs` `list_pam_session`
251	do
252		if [ -f "$lib" ]
253		then
254			dir=`dirname "$home_dir$lib"`
255			if [ ! -d "$dir" ]
256			then
257				mkdir -p "$dir" || exit 2
258			fi
259			copy_file "$lib" 555 root:bin
260		fi
261	done
262
263	# Copy required commands.
264	for prog in /usr/bin/ls `list_conv_cmds`
265	do
266		if [ -f "$prog" ]
267		then
268			dir=`dirname "$home_dir$prog"`
269			if [ ! -d "$dir" ]
270			then
271				mkdir -p "$dir" || exit 2
272			fi
273			copy_file "$prog" 111 root:bin
274		fi
275	done
276
277	# Copy timezone files.
278	if [ -d /usr/share/lib/zoneinfo ]
279	then
280		rm -rf "$home_dir/usr/share/lib/zoneinfo"
281		find /usr/share/lib/zoneinfo | cpio -pduL "$home_dir" >/dev/null 2>&1
282		(cd "$home_dir/usr/share/lib"; find zoneinfo -type f |
283			xargs chmod 444)
284		rm -rf "$home_dir/usr/share/lib/zoneinfo/src"
285	fi
286
287	for dir in usr lib platform
288	do
289		if [ -d "$home_dir/$dir" ]
290		then
291			(cd "$home_dir"; find $dir -type d | xargs chmod 111)
292			(cd "$home_dir"; find $dir -type d | xargs chown root:bin)
293			[ $dir != "lib" ] && chown root:sys "$home_dir/$dir"
294		fi
295	done
296}
297
298install_slash_dev()
299{
300	# Preserve an existing dev directory.
301	make_dir dev 111 root:sys
302
303	# Copy devices.
304	for devname in conslog null udp udp6 zero
305	do
306		rm -f "$home_dir/dev/$devname"
307	done
308	cpio -pduL "$home_dir" >/dev/null 2>&1 <<-EOF
309	/dev/conslog
310	/dev/null
311	/dev/udp
312	/dev/udp6
313	/dev/zero
314	EOF
315	if [ $? -ne 0 ]
316	then
317		fmt=`gettext "%s: Error: Creation of devices in %s failed"`
318		printf "$fmt\n" "$cmd" "$home_dir/dev" >&2
319		exit 2
320	fi
321}
322
323install_slash_pub()
324{
325	# Preserve an existing pub directory.
326	make_dir pub 755 root:sys
327}
328
329update_home_dir()
330{
331	fmt=`gettext "Updating directory %s"`
332	printf "$fmt\n" "$home_dir"
333	install_slash_dev
334	install_slash_etc
335	install_slash_usr
336	install_slash_pub
337}
338
339# Execution starts here.
340
341IFS="
342"
343SHELL=/usr/bin/ksh
344PATH=/usr/bin
345TEXTDOMAIN=SUNW_OST_OSCMD
346export SHELL PATH IFS TEXTDOMAIN
347
348cmd=`basename "$0"`
349username=ftp
350login_shell=/bin/true
351
352verify_root
353
354while getopts d arg
355do
356	case $arg in
357	d)	directory_only=1;;
358	\?)	usage;;
359	esac
360done
361shift `expr $OPTIND - 1`
362
363# Check arguments.
364[ $# -gt 1 ] && usage
365
366home_dir="$1"
367if [ -n "$directory_only" -a -z "$home_dir" ]
368then
369	fmt=`gettext "%s: Error: ftpdir required with -d option"`
370	printf "$fmt\n" "$cmd" >&2
371	usage
372fi
373
374if [ -n "$home_dir" ]
375then
376	echo "$home_dir" | grep "^/" >/dev/null 2>&1
377	if [ $? -ne 0 ]
378	then
379		fmt=`gettext "%s: Error: ftpdir must be an absolute pathname"`
380		printf "$fmt\n" "$cmd" >&2
381		usage
382	fi
383fi
384
385# Ignore certain signals.
386trap '' 1 2 3 15
387
388umask 022
389[ -z "$directory_only" ] && add_user
390
391create_home_dir
392update_home_dir
393
394exit 0
395