Skip to content

Instantly share code, notes, and snippets.

@joshua-d-miller
Last active March 1, 2017 18:14
Show Gist options
  • Save joshua-d-miller/d511e3390be75c9d5d7e707effd4dfed to your computer and use it in GitHub Desktop.
Save joshua-d-miller/d511e3390be75c9d5d7e707effd4dfed to your computer and use it in GitHub Desktop.
This script can be used an extension attribute in jamf that will determine if the User Identity Preference is present on the system with an 802.1x EAP-TLS profile. Note: Make this script have the same exclusion and target policy as your configuration profile.
#!/usr/bin/python
# pylint: disable=C0103, W0612, E1101, E0602, E0611
# pylint: disable=W0101, W0110, W0141
''''Report presence of 802.1x User Identity Preference for EAP-TLS'''
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# This script will determined if the KeyChain item that needs created
# for 802.1x EAP-TLS to work on all systems with multiple items is
# present. This information is then reported to jamf.
#
# Joshua D. Miller - [email protected] - The Pennsylvania State University
# Last Updated Friday February 23, 2016
#
# Many Many Thanks to Michael Lynn and Mosen for taking me down
# the rabbit hole that is PyObjC
#
# References
# https://gist.github.com/pudquick/8ad859f30438f3be149fe9751391d037
# https://gist.github.com/pudquick/4cf32c2b403bf0be23b268d6dd3cf803
# https://github.com/mosen/pudquick-pyobjc-framework-Security/
# blob/master/metadata/raw/x86_64-10.12.fwinfo
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Most of EAP 802.1x and Keychain PyObjC code from Michael Lynn
# Instructions on using SecIdentityCopyPreferred and SecIdentityPreferred
# provided by Mosen
from __future__ import print_function
from Foundation import NSBundle
import objc
def get_profile_uuid():
'''Get the UUID of the Configuration Profiles 802.1x Identity
Preference'''
EAP8021X_bundle = NSBundle.bundleWithPath_(
'/System/Library/PrivateFrameworks/EAP8021X.framework')
E_functions = [
('EAPOLControlCopyStateAndStatus', 'i*o^io^@'),
('EAPOLClientConfigurationCreate', '@^@'),
('EAPOLClientConfigurationCopyProfiles', '@@'),
('EAPOLClientProfileGetUserDefinedName', '@@'),
('EAPOLClientProfileGetID', '@@'), ]
objc.loadBundleFunctions(EAP8021X_bundle, globals(), E_functions)
maximum_interfaces = 20
interfaces = map(lambda x: 'en%s' % x, range(maximum_interfaces))
for i in interfaces:
result, status, eap_config = EAPOLControlCopyStateAndStatus(
i, None, None)
if result == 0:
cfg = EAPOLClientConfigurationCreate(None)
profiles = EAPOLClientConfigurationCopyProfiles(cfg)
for n in profiles:
display_name = EAPOLClientProfileGetUserDefinedName(n)
if display_name == 'Ethernet - CoE':
profile_id = EAPOLClientProfileGetID(n)
return profile_id
def read_identity_preference():
'''Time to modify the keychain and create the identity preference we need
to fix Apple's issue - Still an issue as of 10.12.3'''
# from CoreFoundation import CFGetTypeID
Security_framework = NSBundle.bundleWithPath_(
'/System/Library/Frameworks/Security.framework')
# Objective C Functions we will use to read the System keychain and
# determine if our identity preference is present
keychain_functions = [
('SecKeychainGetTypeID', 'I'),
('SecIdentityGetTypeID', 'I'),
('SecKeychainSetUserInteractionAllowed', 'IZ'),
('SecKeychainCopyDomainDefault', 'IIo^^{__CFArray}'),
('SecKeychainOpen', 'I*o^^{__SecKeychain=}'),
('SecKeychainGetStatus', 'I^{__SecKeychain=}o^I'),
('SecKeychainUnlock', 'I^{__SecKeychain=}I*I'),
('SecIdentityCopyPreferred',
'^{__SecIdentityRef=}^{__CFString}^{__CFArray}^{__CFArray}'),
('SecKeychainLock', 'I^{__SecKeychain=}'), ]
objc.loadBundleFunctions(Security_framework, globals(), keychain_functions)
# Build out our CF type signatures
objc.registerCFSignature(
'SecKeychainRef', '^{__SecKeychain=}', SecKeychainGetTypeID())
objc.registerCFSignature(
'SecIdentityRef', '^{__SecIdentityRef=}', SecIdentityGetTypeID())
kSecUnlockStateStatus = 1
kSecPreferencesDomainSystem = 1
user_profile_name = ('com.apple.network.eap.user'
'.identity.profileid.{0:}'.format(uuid))
# Turn off any prompts for a user to enter a password for keychain
SecKeychainSetUserInteractionAllowed(False)
# Let's Open the System Keychain
err, keychains = SecKeychainCopyDomainDefault(
kSecPreferencesDomainSystem, None)
err, keychain = SecKeychainOpen('System.keychain', None)
# Check Status of the System Keychain (Should be locked)
err, status = SecKeychainGetStatus(keychain, None)
unlocked = status | kSecUnlockStateStatus == kSecUnlockStateStatus
if not unlocked:
# Unlock the System Keychain
keychain = SecKeychainUnlock(keychain, 0, None, False)
# Copy our Identity Preference and make the new one with
# the same attributes
keychain_item = SecIdentityCopyPreferred(
user_profile_name, None, None)
err = SecKeychainLock(keychain)
return keychain_item
if __name__ == '__main__':
uuid = get_profile_uuid()
present = read_identity_preference()
if present is not None:
print('<result>Present</result>')
else:
print('<result>Not Present</result>')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment