Notify User of Expiring or Expired Certificate

stephanpeterson
Contributor

In our environment we use user certs for Cisco AnyConnect. I'd like to have a policy that runs on recurring check-in that alerts the user if the cert is about to expire so that they don't lose VPN access.

I thought I had this working but I think I'm running into issues accessing the user's keychain. I can understand why that's a touchy thing. However, what's curious is that I can access the user's login keychain when running the script via Self Service or if I run the policy via the command line. However, when the script is triggered via check-in, it seems to have issues accessing the user's keychain.

Even doing a simple "security default-keychain" is struggling.

Here's some example code:

#!/bin/sh
# Let's set a log file to write to
logFilePath=/tmp/test.log

# Get date/time stamp and kick off log file
dateTimeStamp=$( date )
printf "!! Script Execution Date/Time Stamp = $dateTimeStamp !!
" >> $logFilePath

defaultKeychainPath=$( /usr/bin/security default-keychain | awk '{ print $1 }' | tr -d " )
printf "defaultKeychainPath = $defaultKeychainPath
" >> $logFilePath

exit 0

I end up getting an empty value for the default keychain path. What am I doing wrong?

2 ACCEPTED SOLUTIONS

mm2270
Legendary Contributor III

Yes, it's because when a policy runs on the check-in frequency, it's being called by the Jamf LaunchDaemon, meaning it runs completely as root. Because of how Apple designs the OS, even the root user can't directly access the logged in user's keychain entries. The difference between running the script locally or from Self Service is that it's running in the user context, not root.

To fix this, use a method like this

#!/bin/bash

loggedInUser=$(/usr/bin/stat -f%Su /dev/console)
loggedInUID=$(id -u "$loggedInUser")

defaultKeychainPath=$(/bin/launchctl asuser "$loggedInUID" sudo -iu "$loggedInUser" /usr/bin/security default-keychain | awk -F'"' '{print $2}')

This instructs the script to run the security command and the stuff after it as the current user, using launchctl asuser

Give that a try, change out the actual command to whatever you need it to be, and see if it works for you.

View solution in original post

mm2270
Legendary Contributor III

@stephanpeterson I can't be sure, but if I had to take an educated guess, I think you might need to drop the double quotes surrounding the security command portion. Meaning, remove the quote mark here: "/usr/bin/security and here: $defaultKeychainPath"
In my experience, in the past such quotes around the command were a requirement, back when the command was launchctl bsexec and the early days of launchctl asuser, but somewhere along the line it changed and it will balk now if the command it's attempting to run is enclosed in quotes. I seem to remember seeing that exact error message you're seeing, where the command would get printed back instead of being executed. It doesn't see it as a command, but as a file path or string or something.

Anyway, try removing those and see if you get better results. No guarantees, but definitely worth a try.

View solution in original post

10 REPLIES 10

mm2270
Legendary Contributor III

Yes, it's because when a policy runs on the check-in frequency, it's being called by the Jamf LaunchDaemon, meaning it runs completely as root. Because of how Apple designs the OS, even the root user can't directly access the logged in user's keychain entries. The difference between running the script locally or from Self Service is that it's running in the user context, not root.

To fix this, use a method like this

#!/bin/bash

loggedInUser=$(/usr/bin/stat -f%Su /dev/console)
loggedInUID=$(id -u "$loggedInUser")

defaultKeychainPath=$(/bin/launchctl asuser "$loggedInUID" sudo -iu "$loggedInUser" /usr/bin/security default-keychain | awk -F'"' '{print $2}')

This instructs the script to run the security command and the stuff after it as the current user, using launchctl asuser

Give that a try, change out the actual command to whatever you need it to be, and see if it works for you.

stephanpeterson
Contributor

@mm2270 That command worked to get the default keychain. Thanks! However, my next attempt to access the keychain using your method is failing.

After getting the default keychain I want to see if it contains any certs named $loggedInUser. For some reason I'm getting an error and I'm not sure why:

#!/bin/bash

loggedInUser=$(/usr/bin/stat -f%Su /dev/console)
loggedInUID=$(/usr/bin/id -u "$loggedInUser")

defaultKeychainPath=$(/bin/launchctl asuser "$loggedInUID" sudo -iu "$loggedInUser" /usr/bin/security default-keychain | awk -F'"' '{print $2}')

certlist=$(/bin/launchctl asuser "$loggedInUID" sudo -iu "$loggedInUser" "/usr/bin/security find-certificate -a -c "$loggedInUser" -p $defaultKeychainPath" | sed s/"-----END CERTIFICATE-----"/"-----END CERTIFICATE-----,"/g)
-bash: /usr/bin/security find-certificate -a -c myUserID -p /Users/myUserID/Library/Keychains/login.keychain-db: No such file or directory

If I run the command that's returned in the error message, it works fine.

Thanks again for your assistance.

mm2270
Legendary Contributor III

@stephanpeterson I can't be sure, but if I had to take an educated guess, I think you might need to drop the double quotes surrounding the security command portion. Meaning, remove the quote mark here: "/usr/bin/security and here: $defaultKeychainPath"
In my experience, in the past such quotes around the command were a requirement, back when the command was launchctl bsexec and the early days of launchctl asuser, but somewhere along the line it changed and it will balk now if the command it's attempting to run is enclosed in quotes. I seem to remember seeing that exact error message you're seeing, where the command would get printed back instead of being executed. It doesn't see it as a command, but as a file path or string or something.

Anyway, try removing those and see if you get better results. No guarantees, but definitely worth a try.

stephanpeterson
Contributor

@mm2270 That worked!! Thanks so much for your help. In addition, I'd like to thank you for all the help you've provided to myself and everyone else on Jamf Nation. I don't know how you have time to get any work done!!

jezza
New Contributor III

Hey @stephanpeterson Is there any chance you could go into a bit more detail on how you did this. I would love to be able to do this in my environment.

stephanpeterson
Contributor

@coasttech Yeah, I had every intention of getting back to this and sharing the solution I was able to create. Things are kind of crazy right now #WorstSpringBreakEver2020 but I'll see if I can sanitize what I have and post it for you and the community.

gabester
Contributor III

@stephanpeterson I might need to coopt that hashtag. I'd appreciate the writeup as well, although I've got sufficient resources and have been tooling around with this stuff as time allows the past couple months so hopefully the info above is enough for me to pull it off. Please keep yourself sane and worry more about sanitizing as needed in the real world that for us!

mani2care
Contributor

Hi stephanpeterson

Can i have the script working one im looking for extension attribute 
i have user certificate in there Email user first and last name how can i filter it via script i just want the certificate name, UID ,and expiration start and end date 

#!/bin/bash

loggedInUser=$(/usr/bin/stat -f%Su /dev/console)
loggedInUID=$(/usr/bin/id -u "$loggedInUser")

defaultKeychainPath=$(/bin/launchctl asuser "$loggedInUID" sudo -iu "$loggedInUser" /usr/bin/security default-keychain | awk -F'"' '{print $2}')

certlist=$(/bin/launchctl asuser "$loggedInUID" sudo -iu "$loggedInUser" "/usr/bin/security find-certificate -a -c "$loggedInUser" -p $defaultKeychainPath" | sed s/"-----END CERTIFICATE-----"/"-----END CERTIFICATE-----,"/g)

 

mm2270
Legendary Contributor III

@mani2care what's the common name of the certificate you're trying to get info on? Is it just the short name of the user account? Because that's what you're telling the security command to look for.

/usr/bin/security find-certificate -a -c "$loggedInUser"

Also, drop the opening and closing quote marks around the security command. As I mentioned in my post back on 11/5/2019, those aren't required anymore, and will make the command fail.

HI "$loggedInUser" is local user user name only getting it i want to get
the LDAP username
to matching with user certificate and fetch the details from keychain. do
we have any option.
Thanks & Regards,

Manikandan R
Contact: +91-9902103878
E-mail: mani2care@gmail.com