JamfPro version of Make Me Admin

jwojda
Valued Contributor II

Looks like Jamf Pro Services posted an updated version of the MMA script that's floating around. I found it off @Andrina 's git page for her original work.

here's the jamf version. Thanks @Rosko

I'm trying to set it up and do some testing, but I'm a little confused about how to setup the encrypted strings portion in the removeTmpAdmin.py script.

Looks like we need to change the parameter #4 for the admin account & the password. Do we just put them both into the $4 field in the script options (ex. $4 admin password) I assume we need to encrypt it (though I thought by using the parameter options that was passed as encrypted) via the link on his GitHub page and then update the salt and passphrase.

14 REPLIES 14

Rosko
Contributor II
Contributor II

Hey @jwojda!

You got a little ahead of me ;) I was planning to post this on JN once I got the wiki built, precisely for this reason, but no big. Here is what you'll want to do!

  1. Head on over and check out Bryson Tyrrell's EncryptedStrings_Bash.sh file on his GitHub page.
  2. Copy lines 8-16
function GenerateEncryptedString() {
    # Usage ~$ GenerateEncryptedString "String"
    local STRING="${1}"
    local SALT=$(openssl rand -hex 8)
    local K=$(openssl rand -hex 12)
    local ENCRYPTED=$(echo "${STRING}" | openssl enc -aes256 -a -A -S "${SALT}" -k "${K}")
    echo "Encrypted String: ${ENCRYPTED}"
    echo "Salt: ${SALT} | Passphrase: ${K}"
}

3. Launch Terminal on your Mac
4. Paste in the copied code and press enter
5. Now enter the following command, replacing jamf1234 with the password you want encrypted

GenerateEncryptedString "jamf1234"

6. This will give you the following output
2e75d07753e8478ba43ea6cd96fca988
7. Now on the removeTempAdmin.py script, take the Salt and put that on line 76 and the Passphrase on line 77. The Encrypted String will go into the Jamf Pro Policy which has this script attached and be used on Script Parameter #4. The userName of the admin account you are checking will actually go on line 75 in-between the single-quotes where I have orgAdmin.

One last thing is to set the removeTempAdmin policy to be available offline so that if the user goes home or offline, you can still get the permissions removed.

I'm hoping to get a complete step-by-step guide up on my GitHub page by end of next week!

mlavine
Contributor

Is this functionality that could be implemented into Jamf Pro in the future?

spalmer
Contributor III

@Rosko I started looking at your script and I don't think the local admin account validation via an encrypted parameter field will work well for an environment like ours with about 50 Sites where each site has their own local admin account and password. This also doesn't account for Macs that have multiple valid local admin accounts.

I don't pretend to know much about how passwords are stored for local accounts, but from what I have found it looks like the ShadowHash is stored in /var/db/dslocal/nodes/Default/users/username.plist. I propose that, rather than storing any password in the JSS at all, while you are creating the list of users that are valid local admins that you also create a backup copy of their username.plist. Then when removing admin rights for the end user you could confirm if the password has been changed for the valid local admin accounts using some commands I found at https://github.com/viverae/pwpolicy/blob/master/PasswordAgeCheck.sh:

# For OS X 10.10 or later:
dscl . -read "/Users/$currentUser" accountPolicyData | grep passwordLastSetTime -A1 | tail -1 | cut -d '>' -f 2 | cut -d '<' -f 1 | cut -d . -f 1

# For OS X 10.9 or older:
dscl . -read "/Users/$currentUser" PasswordPolicyOptions | grep passwordLastSetTime -A1 | tail -1 | awk -F T '{print $1}' | awk -F > '{print $2}'

Some accounts that have never changed their password may not yet have a passwordLastSetTime key/value pair so you could fall back to check the last modification date of the username.plist using:

mdls -name kMDItemFSContentChangeDate /private/var/db/dslocal/nodes/Default/users/username.plist

Or you could even compare the ShadowHash info from the backup username.plist with the current username.plist. The ShadowHash data can be read using:

defaults read /private/var/db/dslocal/nodes/Default/users/username.plist ShadowHashData

If you find the password has been changed you could then restore the backup copy of the username.plist (with the original password) replacing the modified username.plist thus restoring the original password. I have manually verified this works. If you have concerns about replacing the entire plist, maybe you could just read the ShadowHashData from the backup plist and write it to the current plist. I have not verified if this works though.

And of course when you are done you will definitely want to delete the backup copies of the username.plist files.

I would also like to see a version of MakeMeAdmin where the length of time can be defined using a Parameter field so that each Site can change the time accordingly, but if an amount of time is not provided then it defaults to 30 minutes.

jwojda
Valued Contributor II

is there a way to exclude accounts, so it won't remove from admin1, admin2, etc?

jwojda
Valued Contributor II

@Rosko any updates or thoughts on the excluding certain accounts?

Rosko
Contributor II
Contributor II

@mlavine At this time, it is not a planned feature to be added to Jamf Pro. Please feel free to create a Feature Request if you'd like.

@spalmer I have the script ready to be able to support multiple admin accounts, but I need to make a few more changes yet before that is ready. I have an idea that shouldn't take too long, just need some time to re-arrange some things.

@jwojda When this runs, it pulls a list of all the admin accounts currently on the machine and does the same when the admin rights are revoked. It then compares this two lists and any newly added accounts it will remove admin rights for, not ones that were an admin to begin with. Make sense?

jwojda
Valued Contributor II

@Rosko I've run it on a few different test machines. One machine it removed all admin rights from all users (including existing local users). Then on two other machine (10.12 and 10.13) it said it ran but it never applied..

[STEP 1 of 4] Executing Policy MMA-1yr-beta [STEP 2 of 4] Running script grantTempAdmin.py... Script exit code: 0 Script result: Creating LaunchDaemon... Loading LaunchDaemon... Retrieving List of Current Admins... Updating Plist... Granted Admin Right to jwojda
Executing Policy MMA-1yr-beta RemoveAdmin Running script removeTempAdmin.py... Script exit code: 0 Script result: DS Error: -14090 (eDSAuthFailed) Authentication for node /Local/Default failed. (-14090, eDSAuthFailed) Retrieving inventory preferences from https://jss.mycompany:8443/... Finding extension attributes... Locating applications... Locating package receipts... Locating accounts... Searching path: /Applications Locating hard drive information... Locating software updates... Locating plugins... Searching path: /Library/Internet Plug-Ins Locating hardware information (Mac OS X 10.12.6)... Submitting data to https://jss.mycompany.com:8443/... 2282 Revoked Admin Rights for jwojda Checking for newly created admin accounts... No New Accounts Found! Checking organizational admin passwords... Password for orgAdmin: <local.jss.admin> was invalid! Password Successfully Reset for <local.jss.admin>! Removing LaunchDaemon...

Rosko
Contributor II
Contributor II

@jwojda Those logs look right...I don't see how it could of removed the admin rights for all the accounts as the first script creates a plist listing all the admin accounts that are already on the machine and those accounts are excluded from removing the permissions. When you test again take a look at the plist and log files created in /usr/local/jamfps/ and if you want, shoot them over to me in an email and I'll dig in some more.

aharvey
New Contributor

@Rosko This script is great, and looks like it will work great in our environment. The roadblock I'm running into is with the orgAdmins portion. Even though I have verified the passphrase, salt, and encrypted string match the existing admin password, when I run the script, it says the admin password does not match and sets it to something (I haven't been able to determine what the something is). I have tested the script by logging the salt, passphrase, admpass, and admpassDecrypted values to the log file, and verify they are what I'm expecting to see. But the admpassDecrypted password doesn't seem to be what is being matched against or written to the admin account.

For example, my logfile logs admpassDecrypted = password1234 and that matches the admin account password, but when I run the script, it says the orgAdmin password is invalid, and writes an unknown password to the admin account.

However, if I reset things, and change the line valid = subprocess.call(["dscl", "/Local/Default", "-authonly", admin, admpassDecrypted])
to
valid = subprocess.call(["dscl", "/Local/Default", "-authonly", admin, "password1234"])
the script validates the password as correct.

Any thoughts? I'm testing it on OSX 10.12.6.

Thanks for creating this BTW.

Rosko
Contributor II
Contributor II

@jwojda & @aharvey -

Sorry for the delay, been crazy leading up to JNUC, but now I had some time to try and replicate this. So I copied down a fresh copy from GitHub and everything works as expected when I use the python version of EncryptedStrings. If I use the bash version, special characters seem to get cut out/lost in the process. So bottom line the script does work, you just need to use the python version of EncryptedStrings to generate the inputeString, salt and passphrase. Here is a direct link to the Python version.

Sorry you ran into this issue, but thanks for finding it. I am hoping to make a couple changes in the coming weeks to allow support of multiple orgAdmins and also build out the wiki section so folks can easily get this in-place.

Please reach out if you run into any more issues and feel free to create issues on the GitHub repo.

jwojda
Valued Contributor II

@Rosko hey I recently had to look into this again and came across this post, I was about to try the bash version when I scrolled down and saw you suggested using the python version. I copied what I believed to be the pertinent lines (9-16) and it just reports syntax errors when I paste into terminal.

maffettb
New Contributor III

@jwojda I'm not sure if you ever got this figured out but I was hitting my head against a wall and then I found this post but ran into the .sh thing and yes, it still does not properly encrypt the password. I found another post that sort of pointed me in the right direction about actually modifying the .sh file and adding the GenerateEncryptedString "jamf1234" at the end of the script, and when ran it will just auto show the results...so I did this with the .py script instead but you have to follow the usage syntax in the python version...a little different the the .sh version, GenerateEncryptedString("jamf1234") and then you can run the python script from terminal using the "python filename.py" command.

Tested and this does properly encrypt the string and the other script works now but, I'm having issues with it actually changing the password back to the correct password when a user changes it.

Schmidty
New Contributor III

I've been testing this out but have been having inconsistency with resetting of the local admin password. It was successful when I tried it yesterday but when I tried it today on another computer I get:
Checking organizational admin passwords...
Password for orgAdmin: ladmin was invalid!
Error Resetting Password for ladmin!

Any one have this issue?

lrhodes
New Contributor II

Hi, I am trying to get this working in my environment but am having issues.

The first policy is granting admin rights to the logged in user. However, the admin rights aren’t getting revoked by the second policy.

It runs, grants admin rights and creates the com.jamfps.adminremove.plist

But for some reason It just doesn’t call the 2nd policy. If I run the "removeadmin" trigger manually from Terminal it runs. I’m just trying to work out if I’ve missed a step that’s not making the launchdaemon do it’s job properly.

I've cached the policy so it's available offline. Any help would be great, thanks in advance....