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