#!/usr/bin/perl ################################################################################ # LoginHook # Joseph Jackson, 26-Apr-2002 # # This login hook creates a local home directory for the user logging in # and establishes default preferences. # # The local home directory is created with appropriate ownership and mode # bits. Then ~/Library is created as a symlink to the user's AFS file space, # ensuring that preferences, keychains, and other settings follow the user # from machine to machine. For local users (admin and root) or guest accounts # where AFS space is limited, ~/Library is created on the local disk instead. # As an optimization, ~/Library/Caches is kept on the local hard drive by # linking it back to ~/.local/Caches. # # This script is executed as root. All the modifications made to the local # hard drive need to be done as root. Changes to AFS require the tokens of the # user logging in, so we permanently switch to that uid before beginning the # AFS work. # # revision history # 08 nov 2005, jf6b: gutted, reorganized, and rebuilt for Tiger # 06 dec 2005, jf6b: changed call to reboot to shutdown # ################################################################################ require "/etc/cmu/hooks/hook-subs"; get_opts(); ################ # Create logfile # log_init("/etc/cmu/hooks/logs/LoginHook.log", $WARNING); ################# # Check Arguments # log_abort("Script invoked with bad number of arguments") if ($#ARGV != 0); $user = $ARGV[0]; log_abort("Script invoked with a blank user-id argument") if ($user eq ''); ############### # Check for AFS # # Sadly, OSX thinks that asynchronous startup is "good". This means that # sometimes, AFS isn't fully mounted by the time we get to this point. # So, we pause up to 60 seconds and wait for the rest of the system to # catch up. # foreach $i (0..59) { if ( -d "/afs/andrew.cmu.edu" ) { last; } else { sleep 1; } } if ($i > 0) { if ($i < 59) { log_warning("Had to sleep for $i seconds waiting for /afs to start.") } else { log_error("Waited $i seconds for AFS to start, but had to give up!"); } } ################## # Lookup User Info # ($name,$passwd,$uid,$gid, $quota,$comment,$gcos, $homedir,$shell,$expire) = getpwnam($user) or log_abort("User '$user' not in passwd database: $!"); log_abort("Home directory setting is blank for user '$user'") if ($homedir eq ''); if ($user =~ m/^(guest[0-9][0-9]+|admin|root)$/) { $isguest = 1; } else { $isguest = 0; } # Userid radmind triggers a mac-update run followed by a forced reboot #if ($user eq "radmind") { # system "/usr/local/Applications/iHook.app/Contents/MacOS/iHook --script=/etc/cmu/stealth-update.hook"; ## XXX - Hack to make AFS happy # system "/Library/StartupItems/OpenAFS/OpenAFS stop"; # system "/sbin/shutdown -r now"; # while(1) {sleep 1}; # Infinite loop to make sure we never fully login #} if (!$isguest) { $afshomedir = find_afshomedir($user); if ($afshomedir eq '') { log_warning("Couldn't determine AFS home directory for user '$user'"); $isguest = 1; } elsif ($afshomedir !~ m'^/afs/') { log_warning("AFS home directory setting for user '$user' is not valid: '$afshomedir'"); $isguest = 1; } } ############### # Clean up disk # # Clear some disk space with find if there's not enough free, where # "enough" means "half the usable space." # #run_command("/etc/cmu/disk-cleanup percent 50"); ############################# # Create Homedir and Subdirs # # Remove existing homedir if ownership is wrong or it's not a directory # (undef, undef, undef, undef, $hd_uid, $hd_gid) = stat($homedir); system "rm -rf $homedir" if ($hd_uid != $uid || $hd_gid != $gid || (-e _ && ! -d _ )); if ($user == "admin") { &make_dir ($uid, $gid, $mode_pvt, "$homedir"); } else { &make_dir ($uid, $gid, $mode_shr, "$homedir"); } (-l "/Users/CurrentUser") and unlink "/Users/CurrentUser" or log_warning("Failed to unlink /Users/CurrentUser: $!"); &make_link("$homedir", "/Users/CurrentUser"); &make_link ("$afshomedir", "$homedir/MyAFS") if (!$isguest); &make_dir ($uid, $gid, $mode_pvt, "$homedir/.local"); &make_dir ($uid, $gid, $mode_pvt, "$homedir/.local/Caches"); &make_dir ($uid, $gid, $mode_pvt, "$homedir/.local/Temporary Files"); &make_dir ($uid, $gid, $mode_pvt, "$homedir/Documents"); ###################### # Remove local Library # # For non-guests, get ready to create Library as a link into AFS by removing # any local Library directory # It might be owned by root, so do it before switching UID/GID # if (!$isguest) { # Don't use run_command to avoid logging EISDIR errors system "rm -f $homedir/Library"; system "rm -rf $homedir/Library"; } ################################################################################ # SWITCH FROM ROOT TO THE UID AND PRIMARY GID OF USER LOGGING IN # # This grants us access to the user's AFS space, # but limits what we can do to the local file system # switch_to_user($uid, $gid); ######################################################## # Grab AFS Tokens # # Grab tokens for the user, since the aklog plugin seems broken # run_command("aklog"); ################# # Check AFS Quota # # If the user is over quota or we can't check the quota, # treat it like a guest account (don't link ~/Library into AFS, etc.) # if (!$isguest) { $isguest = &overquota($afshomedir); } ################ # Create Library # # For guests, create Library and Library/Prefs as local directories # For others, point Library into AFS home directory # if (!$isguest) { &make_afsdir ("$afshomedir/Library", "system:anyuser none"); &make_afsdir ("$afshomedir/Library/Preferences", "system:anyuser none"); &make_link ("$afshomedir/Library", "$homedir/Library"); # Don't use run_command to avoid logging EISDIR errors system "rm -f $afshomedir/Library/Caches"; system "rm -rf $afshomedir/Library/Caches"; &make_link ("$homedir/.local/Caches", "$afshomedir/Library/Caches"); &make_afsdir ("$afshomedir/Library/Application Support", "system:anyuser none"); if (! -l "$afshomedir/Library/Application Support/Temporary Files") { unlink "$afshomedir/Library/Application Support/Temporary Files"; &make_link ("$homedir/.local/Temporary Files", "$afshomedir/Library/Application Support/Temporary Files"); } # Provide ~/Library/Printers for InDesign/Illustrator &make_afsdir ("$afshomedir/Library/Printers", "system:anyuser none"); } else { # For users over quota, we need to remove any Library that's a symlink into AFS unlink "$homedir/Library"; # ignore errors &make_dir ($uid, $gid, $mode_pvt, "$homedir/Library"); &make_dir ($uid, $gid, $mode_pvt, "$homedir/Library/Preferences"); } ################################ # Execute individual login hooks # run_parts("login"); ############################### # Run a user's .MacOSXLoginHook # This allows them to make extra modifications at login time. # #if (!$isguest) { # hookwrap("$afshomedir/.MacOSXLoginHook"); #} log_close(); exit 0;