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