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 53 usage() 54 { 55 fmt=`gettext "Usage: %s [ftpdir]\n %s -d ftpdir"` 56 printf "$fmt\n" "$cmd" "$cmd" >&2 57 exit 1 58 } 59 60 verify_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. 73 make_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. 91 copy_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 103 add_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 145 list_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 157 list_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 167 list_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 176 create_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 200 install_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 232 install_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 298 install_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 323 install_slash_pub() 324 { 325 # Preserve an existing pub directory. 326 make_dir pub 755 root:sys 327 } 328 329 update_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 341 IFS=" 342 " 343 SHELL=/usr/bin/ksh 344 PATH=/usr/bin 345 TEXTDOMAIN=SUNW_OST_OSCMD 346 export SHELL PATH IFS TEXTDOMAIN 347 348 cmd=`basename "$0"` 349 username=ftp 350 login_shell=/bin/true 351 352 verify_root 353 354 while getopts d arg 355 do 356 case $arg in 357 d) directory_only=1;; 358 \?) usage;; 359 esac 360 done 361 shift `expr $OPTIND - 1` 362 363 # Check arguments. 364 [ $# -gt 1 ] && usage 365 366 home_dir="$1" 367 if [ -n "$directory_only" -a -z "$home_dir" ] 368 then 369 fmt=`gettext "%s: Error: ftpdir required with -d option"` 370 printf "$fmt\n" "$cmd" >&2 371 usage 372 fi 373 374 if [ -n "$home_dir" ] 375 then 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 383 fi 384 385 # Ignore certain signals. 386 trap '' 1 2 3 15 387 388 umask 022 389 [ -z "$directory_only" ] && add_user 390 391 create_home_dir 392 update_home_dir 393 394 exit 0