LKDC
The local KDC in Leopard is pretty rad. This page will be a jumble of research and various investigations regarding the LKDC.
Contents
Discovery
The LKDC realm name of a remote Mac OS X machine may be discovered as follows:
dns-sd -Q "_kerberos.donk.local" txt
Replace "donk" with the rendezvous name of a Leopard machine on your local network (can test on yourself if needed).
The result is a string of hex characters. This command does not terminate, so control-C to stop it. Now take the hex and run it through xxd -r -c 256.
xxd -r -c 256
<paste in the hex string, press return>
The result is the LKDC realm name, such as LKDC:SHA1.8B0FBACC08E3152A473A68D303E297A13CAA3AFD
Interesting Files
NetAuthAgent
This appears to be a client side Kerberos helper. The role of NetAuthAgent appears to be to manage the Kerberos authentication process at a high level on behalf of screen sharing (vncserver), afp client, and cifs client. A string dump reveals the following chunk of kerberos service names:
vncserver webdaveserver ftpsserver ftpserver cifs afpserver
vncserver, cifs, and afpserver are the only 3 services that are kerberized in the LKDC by default, though NetAuthAgent appears to support others as well. Looking at all strings matching 'kerb', we see:
{5} andre@donk [~] % strings /System/Library/CoreServices/NetAuthAgent.app/Contents/MacOS/NetAuthAgent | grep -i kerb KerberosSession BypassKerberos kerberosClientPrincipalCredentials kerberosRelease kerberosClientPrincipal kerberosKeychainRealm kerberosPrincipalInfo MountedByKerberos SupportsKerberos /System/Library/CoreServices/Kerberos.app mInvalidKerberosUserName checkForKerberosUserName: isValidKerberosUserName: useKerberos kerberosServiceName kerberosServicePrincipalHint kerberosSession kerberosServicePrincipal kerberosAcquireTicket Kerberos AllowKerberosUI KerberosInfo kerberosUIOption kerberosHostDisplayName kerberosHostAddress kerberosAlreadyHasTicket
{14} andre@donk [~] % otool -L /System/Library/CoreServices/NetAuthAgent.app/Contents/MacOS/NetAuthAgent | cut -d ' ' -f1 /System/Library/CoreServices/NetAuthAgent.app/Contents/MacOS/NetAuthAgent: /System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa /System/Library/Frameworks/Security.framework/Versions/A/Security /System/Library/PrivateFrameworks/URLMount.framework/Versions/A/URLMount /System/Library/Frameworks/SecurityInterface.framework/Versions/A/SecurityInterface /System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices /System/Library/PrivateFrameworks/KerberosHelper.framework/Versions/A/KerberosHelper /usr/lib/libgcc_s.1.dylib /usr/lib/libSystem.B.dylib /System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices /usr/lib/libobjc.A.dylib /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation
LKDCLocate
This Kerberos framework plugin looks like it's able to perform DNS queries to retrieve kerberos info. It also seems to interact with a mach service created by LKDCHelper called com.apple.KerberosHelper.LKDCHelper.
{14} andre@donk [~] % strings /System/Library/KerberosPlugins/KerberosFrameworkPlugins/LKDCLocate.bundle/Contents/MacOS/LKDCLocate %s: LKDCLookup Declined to handle address family %d svc = %d, realm = %s, family= %d, socktype = %d KDC|MasterKDC LKDC: getaddrinfo () == %d 0x%08p: family = %d, socktype = %d, protocol = %d Running callback 0x%08p Unexpected address family %d Callback done 0x%08p, err=%d inet_ntop failed: %s addr = %s, port = %d failed %d LKDCGetHelperPort com.apple.KerberosHelper.LKDCHelper %s: cannot contact helper LKDCHelperExit Mach communication failed: %s LKDCDumpStatus LKDCSetLogLevel LKDCGetLocalRealm [[[ %s Local realm = %s ]]] %s = %d (%s) LKDCDiscoverRealm No place to store discovered realm. realm = %s LKDCFindKDCForRealm No place to store discovered KDC hostname. KDC Hostname = %s:%u Communication to the helper failed Not authorized Input parameter error Serializing object failed Unserializing object failed Object passed is not a dictionary A Local KDC was not found Lookup of the KDC for the requested realm failed %s: Success <unknown error> [...]
KerberosHelper
This private framework appears to provide API that can be used on behalf of service clients to discover the LKDC information of a remote realm.
{6} root@donk [~] # strings /System/Library/PrivateFrameworks/KerberosHelper.framework/Versions/A/KerberosHelper LKDCGetHelperPort com.apple.KerberosHelper.LKDCHelper %s: cannot contact helper LKDCHelperExit Mach communication failed: %s LKDCDumpStatus LKDCSetLogLevel LKDCGetLocalRealm [[[ %s Local realm = %s ]]] %s = %d (%s) LKDCDiscoverRealm No place to store discovered realm. realm = %s LKDCFindKDCForRealm No place to store discovered KDC hostname. KDC Hostname = %s:%u LKDC: %s: krb5 call got %d (%s) on %s:%d realm_for_host (null) [[[ %s: hostname=%s hintrealm=%s /SourceCache/KerberosHelper/KerberosHelper-31/Source/KerberosHelper.c %s: krb5_get_host_realm success %s: krb5_get_host_realm returned unusable realm! %s: LKDCDiscoverRealm success ]]] %s: returning realm=%s ]]] %s: failed to determine realm [[[ KRBCopyRealm () - required parameters okay ]]] KRBCopyRealm () = %d [[[ KRBCopyKeychainLookupInfo () - required parameters okay Username KeychainAccountName DisableSaveToKeychain edu.mit.Kerberos.KerberosAgent SavePasswordDisabled KRBCopyKeychainLookupInfo: DisableSaveToKeychainKey = TRUE KRBCopyKeychainLookupInfo: CFPreferencesCopyAppValue == NULL ]]] KRBCopyKeychainLookupInfo () = %d [[[ KRBCopyServicePrincipal () - required parameters okay KRBCopyServicePrincipal: svcName mismatch inService = "%s", svcName = "%s" KRBCopyServicePrincipal: useName = "%s" LKDC: KRBCopyServicePrincipal: realm is Local KDC. KRBCopyServicePrincipal: Bad inHostName, using svcInstance = "%s" KRBCopyServicePrincipal: useInstance = "%s" KRBCopyServicePrincipal: Fatal - Bad inHostName & no inAdvertisedPrincipal %s/%s@%s KRBCopyServicePrincipal: principal = "%s/%s@%s" ]]] KRBCopyServicePrincipal () = %d KRBCopyClientPrincipalInfo [[[ KRBCopyClientPrincipalInfo () - required parameters okay Certificate KRBCopyClientPrincipalInfo: Certificate information in dictionary KRBCopyClientPrincipalInfo: Certificate not present in dictionary .Mac Sharing Certificate %@@%@ KRBCopyClientPrincipalInfo: Using login name = "%s" KRBCopyClientPrincipalInfo: principal guess = "%s" KRBCopyClientPrincipalInfo: ccache principal match = "%s" KRBCopyClientPrincipalInfo: found a single ticket for realm, replacing principal & username KRBCopyClientPrincipalInfo: Setting found Username to = "%s" KRBCopyClientPrincipalInfo: using principal = "%s" ClientPrincipal KRBCopyClientPrincipalInfo: usingCertificate == %d UsingCertificate CetificateHash CertificateInferredLabel KRBCopyClientPrincipalInfo: InferredLabel = "%s" ]]] KRBCopyClientPrincipalInfo () = %d %@@%s [[[ KRBTestForExistingTicket () - required parameters okay KRBTestForExistingTicket: principal = "%s" KRBTestForExistingTicket: Valid Ticket, ccacheName = "%s" ]]] KRBTestForExistingTicket () = %d KRBAcquireTicket [[[ KRBAcquireTicket () - required parameters okay KRBAcquireTicket: Using a certificate Password ]]] KRBAcquireTicket () = %d [[[ KRBCloseSession () - required parameters okay ]]] KRBCloseSession () = %d parse_principal_name KRBCreateSession [[[ %s () - required parameters okay %s: LocalKDC realm lookup only %s: __KRBCreateUTF8StringFromCFString failed [[[ %s () decomposing %s ]]] %s () - %d %s: processed host name = %s %s.local %s: last char of host name = 0x%02x success %s: getaddrinfo = %s (%d) %s: canonical host name = %s %s: secondary match = %s %s: primary match = %s %s: could not find a suitable host/realm mapping %s: Using host name = %s, realm = %s ]]] %s () = %d KerberosKDC dsRecTypeStandard:Config realname Communication to the helper failed Not authorized Input parameter error Serializing object failed Unserializing object failed Object passed is not a dictionary A Local KDC was not found Lookup of the KDC for the requested realm failed %s: Success <unknown error>
LKDCHelper
This executable is part of the KerberosHelper framework and is a launch agent that runs in the user's namespace. This appears to fire up a mach service called com.apple.KerberosHelper.LKDCHelper which is used to receive commands and return results. My guess is that the commands it can receive are the ones that start with "do_" in the string dump below.
{34} andre@donk [~] % strings /System/Library/PrivateFrameworks/KerberosHelper.framework/Versions/A/Resources/LKDCHelper Idle exit do_LKDCDumpStatus [[[ %s do_LKDCSetLogLevel do_LKDCGetLocalRealm Cached lookup LocalKDCRealm = %s do_LKDCDiscoverRealm Looking up realm for %s do_LKDCFindKDCForRealm Looking up host for %s %s: Unauthorized access by euid=%lu pid=%lu update_idle_timer 0 == gettimeofday(&last_message, NULL) /SourceCache/KerberosHelper/KerberosHelper-31/Source/LKDCHelper-main.c idletimer_main 0 == gettimeofday(&now, NULL) Invalid idle timeout: %s Usage: [-d] [-t maxidle] Could not initialize ASL logging. Starting (uid=%ul) mach_port_allocate: %s mach_port_insert_right: %s com.apple.KerberosHelper.LKDCHelper bootstrap_register2 failed: %s CheckIn Could not create checkin message for launchd. Could not message launchd. Launchd checkin failed: %s. MachServices Launchd reply does not contain %s dictionary. Launchd reply does not contain %s Mach port. Launchd gave me a null Mach port. Failed to start idletimer thread: %s mach_msg_server: %s KerberosKDC dsRecTypeStandard:Config realname _kerberos LookupRealmCallBack mDNSError = %d More than one record, last one wins!!! LKDCAddLocatorDetails New entry for (realm=%s host=%s) Replacing existing entry (realm=%s host=%s) with (realm=%s host=%s) ]]] %s = %d (%s) LKDCHostnameForRealm Cache hit Cache miss HandleEvents LKDCLookupRealm LKDCRealmForHostname %s.%s mDNSResult CallbackError = %d Timeout! LKDCDumpCacheStatus Cache root node = %08p node = %08p { realmName = (%08p) %s serviceHost = (%08p) %s servicePort = %u TTL = %u } Communication to the helper failed Not authorized Input parameter error Serializing object failed Unserializing object failed Object passed is not a dictionary A Local KDC was not found Lookup of the KDC for the requested realm failed %s: Success <unknown error>
- /usr/libexec/configureLocalKDC - this is a perl script that installs the LKDC at installation time, including creating service principals, editing service config files, and installing a kerberos certificate into the system keychain.
Resources
- http://www.felipe-alfaro.org/blog/2007/12/07/kerberizing-leopards-ssh/ This documents how to kerberize ssh / sshd, in Leopard, but uses a static configuration instead of dynamically discovering the remote realm name, as is done by the services kerberized in the LKDC by default.
- http://www.mactech.com/articles/mactech/Vol.23/23.11/ExploringLeopardwithDTrace/index.html Exploring Leopard with DTrace - was useful in determining how some of the service clients interact with Kerberos.
- http://developer.apple.com/technotes/tn2005/tn2083.html Daemons and Agents. Fantastic technote by Quinn. This helped me understand a bit more about the mach service that is provided by LKDCHelper.
- http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/129443 Multicast DNS libraries for Ruby
- http://www.ldap.com/1/commentary/wahl/20070511_01.shtml Discovering local identity services. Outlines several methods for dynamic discovery of how to bootstrap authentication sessions with a remote system.
- http://www.cybersafe.ltd.uk/docs_standards/draft-ietf-krb-wg-krb-dns-locate-03.txt This expired draft documents how kerberos realm information might be discovered using multicast dns.
- http://www.dns-sd.org/ServiceTypes.html multicast DNS service types
- http://files.multicastdns.org/draft-cheshire-dnsext-multicastdns.txt This expired draft documents multicast DNS in general
- http://web.mit.edu/kerberos/www/krb5-1.2/krb5-1.2.6/doc/install.html#SEC9 Kerberos install document; this section documents how Kerberos finds realm information.