简体   繁体   中英

Substitute user mid-Bash-script & continue running commands (Mac OSX)

I'm building two scripts which combined will fully uninstall a program (Microsoft Lync) on Mac OS X. I need to be able to swap from an account with root access (this account initially executes the first script) to the user whom is currently logged in.

This is necessary because the second script needs to be executed not only by the logged-in user, but from said user's shell. The two scripts are name Uninstall1.sh and Uninstall2.sh in this example.

Uninstall1.sh (executed by root user):

#!/bin/bash

#commands ran by root user

function rootCMDs () {

pkill Lync
rm -rf /Applications/Microsoft\ Lync.app
killall cfprefsd

swapUser

}

function swapUser () {

currentUser=$(who | grep console | grep -v _mbsetupuser | grep -v root | awk '{print $1}' | head -n 1)

cp /<directory>/Uninstall2.sh${currentUser}

su -l ${currentUser} -c "<directory>/{currentUser}/testScript.sh";


<directory> actually declared in the scripts, but for the sake of privacy I've excluded it.

In the above script, I run some basic commands as the root user to remove the app to the trash, and kill cfprefsd to prevent having to reboot the machine. I then call the swapUser function, which dynamically identifies the current user account signed into and assigns this to the variable currentUser (in this case within our environment, it's safe to assume only one user is logged into the computer at a time). I'm not sure whether or not I'll need the cp directory/Uninstall2.sh portion yet, but this is intended to solve a different problem.

The main problem is getting the script to properly handle the su command. I use the -l flag to simulate a user login, which is necessary because this not only substitutes to the user account which is logged into, but it launches a new shell as said user. I need to use -l because OS X doesn't allow modifying another user's keychain from an admin account (the admin account in question has root access, but isn't nor does it switch to root). -c is intended to execute the copied script, which is as follows:

Uninstall2.sh (needs to be executed by the locally logged-in user):

#!/bin/bash


function rmFiles () {
    # rm -rf commands
    # rm -rf commands

certHandler1
}


function certHandler1 () {

myCert=($(security dump-keychain | grep <string> | grep alis | sed -e 's/"alis"<blob>="//' | sed -e 's/"//'))
cLen=${#myCert[@]} # Count the amount of items in the array; there are usually duplicates

for ((i = 0;
      i < ${cLen};
      i++));
      do security delete-certificate -c ${myCert[$i]};
done

certHandler2
}


function certHandler2 () {

# Derive the name of, and delete Keychain items related to Microsoft Lync.

myAccount=$(security dump-keychain | grep KeyContainer | grep acct | sed -e 's/"acct"<blob>="//' | sed -e 's/"//')
   security delete-generic-password -a ${myAccount}

lyncPW=$(security dump-keychain | grep Microsoft\ Lync | sed -e 's/<blob>="//' | awk '{print $2, $3}' | sed -e 's/"//')
   security delete-generic-password -l "${lyncPW}"
}


rmFiles


In the above script, rmFiles kicks the script off by removing some files and directories from the user's ~/Library directory. This works without a problem, assuming the su from Uninstall1.sh properly executes this second script using the local user's shell.

I then use security dump-keychain to dump the local user's shell, find a specific certificate, then assign all results to the cLen array (because there may be duplicates of this item in a user's keychain). Each item in the array is then deleted, after which a few more keychain items are dynamically found and deleted.

What I've been finding is that the first script will either properly su to the logged-in user which it finds, at which point the second script doesn't run at all. Or, the second script is ran as the root user and thus doesn't properly delete the keychain items from the logged-in user it's supposed to su to.

Sorry for the long post, thanks for reading, and I look forward to some light shed on this situation!

Revision
I managed to find a way to achieve all that I am trying to do in a single bash script, rather than two. I did this by having the main script create another bash script in /tmp, then executing that as the local user. I'll provide it below to help anybody else whom may need this functionality:

Credit to the following source for the code on how to create another bash script within a bash script:
http://tldp.org/LDP/abs/html/here-docs.html - Example 19.8

#!/bin/bash

# Declare the desired directory and file name of the script to be created. I chose /tmp because I want this file to be removed upon next start-up.
OUTFILE=/tmp/fileName.sh

(
cat <<'EOF'
#!/bin/bash

# Remove user-local Microsoft Lync files and/or directories
function rmFiles () {

   rm -rf ~/Library/Caches/com.microsoft.Lync
   rm -f ~/Library/Preferences/com.microsoft.Lync.plist
   rm -rf ~/Library/Preferences/ByHost/MicrosoftLync*
   rm -rf ~/Library/Logs/Microsoft-Lync*
   rm -rf ~/Documents/Microsoft\ User\ Data/Microsoft\ Lync\ Data
   rm -rf ~/Documents/Microsoft\ User\ Data/Microsoft\ Lync\ History
   rm -f ~/Library/Keychains/OC_KeyContainer*

certHandler1
}


# Need to build in a loop that determines the count of the output to determine whether or not we need to build an array or use a simple variable.
# Some people have more than one 'PRIVATE_STRING' certificate items in their keychain - this will loop through and delete each one. This may or may not be necessary for other applications of this script.

function certHandler1 () {

# Replace 'PRIVATE_STRING' with whatever you're searching for in Keychain
myCert=($(security dump-keychain | grep PRIVATE_STRING | grep alis | sed -e 's/"alis"<blob>="//' | sed -e 's/"//'))
cLen=${#myCert[@]} # Count the amount of items in the array

   for ((i = 0;
        i < ${cLen};
        i++));
      do security delete-certificate -c ${myCert[$i]};
   done

certHandler2
}

function certHandler2 () {

# Derive the name of, then delete Keychain items related to Microsoft Lync.
myAccount=$(security dump-keychain | grep KeyContainer | grep acct | sed -e 's/"acct"<blob>="//' | sed -e 's/"//')
   security delete-generic-password -a ${myAccount}

lyncPW=$(security dump-keychain | grep Microsoft\ Lync | sed -e 's/<blob>="//' | awk '{print $2, $3}' | sed -e 's/"//')
   security delete-generic-password -l "${lyncPW}"

}

rmFiles


exit 0

EOF
) > $OUTFILE

# -----------------------------------------------------------

# Commands to be ran as root
function rootCMDs () {
 pkill Lync
 rm -rf /Applications/Microsoft\ Lync.app
 killall cfprefsd # killing cfprefsd mitigates the necessity to reboot the machine to clear cache.

 chainScript

}

function chainScript () {

if [ -f "$OUTFILE" ]
then
  # Make the file in /tmp executable. This is necessary for /tmp as a non-root user cannot access files in this directory.
  chmod 755 $OUTFILE
  # Dynamically identify the user currently logged in. This may need some tweaking if multiple User Accounts are logged into the same computer at once.
  currentUser=$(who | grep console | grep -v _mbsetupuser | grep -v root | awk '{print $1}' | head -n 1);
  su -l ${currentUser} -c "bash /tmp/UninstallLync2.sh"

else
  echo "Problem in creating file: \"$OUTFILE\""
fi

}


#  This method also works for generating
#+ C programs, Perl programs, Python programs, Makefiles,
#+ and the like.

# Commence the domino effect.
rootCMDs

exit 0

# -----------------------------------------------------------


Cheers!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM