1/*
2 * Copyright (c) 2009-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * EAPOLClientItemID.c
26 * - implementation of the EAPOLClientItemID CF object
27 */
28
29/*
30 * Modification History
31 *
32 * December 2, 2009	Dieter Siegmund (dieter@apple.com)
33 * - created
34 */
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <unistd.h>
39#include <sys/types.h>
40#include <sys/param.h>
41#include <string.h>
42#include <syslog.h>
43#include <servers/bootstrap.h>
44#include <bootstrap_priv.h>
45#include <TargetConditionals.h>
46#include <CoreFoundation/CFString.h>
47#include <Security/SecIdentity.h>
48#include <Security/SecIdentityPriv.h>
49#include <Security/SecTrustedApplication.h>
50#include <Security/SecTrustedApplicationPriv.h>
51#include <SystemConfiguration/SCValidation.h>
52#include <pthread.h>
53#include <mach/mach_init.h>
54#include <mach/vm_map.h>
55#include "EAPCertificateUtil.h"
56#include "EAPOLClientConfigurationInternal.h"
57#include "EAPOLClientConfigurationPrivate.h"
58#include "EAPSecurity.h"
59#include "EAPKeychainUtil.h"
60#include "EAPKeychainUtilInternal.h"
61#include "eapolcfg_auth.h"
62#include "symbol_scope.h"
63#include "myCFUtil.h"
64#include "EAPLog.h"
65
66/**
67 ** Utility functions
68 **/
69STATIC CFTypeRef
70my_CFDictionaryCopyValue(CFDictionaryRef dict, CFStringRef key)
71{
72    CFTypeRef	value;
73
74    value = CFDictionaryGetValue(dict, key);
75    if (value != NULL) {
76	CFRetain(value);
77    }
78    return (value);
79}
80
81#define kEAPOLControllerPath		"/System/Library/SystemConfiguration/EAPOLController.bundle"
82#define keapolclientPath		"eapolclient"
83#define kAirPortApplicationGroup	"AirPort"
84#define kSystemUIServerPath 		"/System/Library/CoreServices/SystemUIServer.app"
85
86STATIC SecTrustedApplicationRef
87create_trusted_app_from_bundle_resource(CFStringRef bundle_path,
88					CFStringRef resource_path)
89{
90    CFBundleRef			bundle;
91    CFURLRef			bundle_url;
92    CFURLRef			eapolclient_url = NULL;
93    char			path[MAXPATHLEN];
94    Boolean			success = FALSE;
95    SecTrustedApplicationRef	trusted_app = NULL;
96
97    bundle_url = CFURLCreateWithFileSystemPath(NULL,
98					       bundle_path,
99					       kCFURLPOSIXPathStyle, FALSE);
100    if (bundle_url == NULL) {
101	goto done;
102    }
103    bundle = CFBundleCreate(NULL, bundle_url);
104    CFRelease(bundle_url);
105    if (bundle == NULL) {
106	goto done;
107    }
108    eapolclient_url
109	= CFBundleCopyResourceURL(bundle, CFSTR(keapolclientPath),
110				  NULL, NULL);
111    CFRelease(bundle);
112    if (eapolclient_url == NULL) {
113	goto done;
114    }
115    success = CFURLGetFileSystemRepresentation(eapolclient_url,
116					       TRUE,
117					       (UInt8 *)path, sizeof(path));
118    CFRelease(eapolclient_url);
119    if (success) {
120	OSStatus	status;
121
122	status = SecTrustedApplicationCreateFromPath(path,
123						     &trusted_app);
124	if (status != noErr) {
125	    fprintf(stderr,
126		    "SecTrustedApplicationCreateFromPath(%s) failed, %d\n",
127		    path, (int)status);
128	}
129    }
130
131 done:
132    return (trusted_app);
133}
134
135STATIC CFArrayRef
136copy_trusted_applications(bool eapolclient_only)
137{
138    CFMutableArrayRef		array;
139    SecTrustedApplicationRef	trusted_app;
140    OSStatus			status;
141
142    array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
143
144    /* eapolclient */
145    trusted_app
146	= create_trusted_app_from_bundle_resource(CFSTR(kEAPOLControllerPath),
147						  CFSTR(keapolclientPath));
148    if (trusted_app != NULL) {
149	CFArrayAppendValue(array, trusted_app);
150	CFRelease(trusted_app);
151    }
152
153    /* AirPort Application Group */
154    status
155	= SecTrustedApplicationCreateApplicationGroup(kAirPortApplicationGroup,
156						      NULL, &trusted_app);
157    if (status != noErr) {
158	fprintf(stderr,
159		"SecTrustedApplicationCreateApplicationGroup("
160		kAirPortApplicationGroup ") failed, %d\n",
161		(int)status);
162    }
163    else {
164	CFArrayAppendValue(array, trusted_app);
165	CFRelease(trusted_app);
166    }
167    if (eapolclient_only) {
168	goto done;
169    }
170
171    /* this executable */
172    status = SecTrustedApplicationCreateFromPath(NULL, &trusted_app);
173    if (status != noErr) {
174	fprintf(stderr,
175		"SecTrustedApplicationCreateFromPath(NULL) failed, %d\n",
176		(int)status);
177    }
178    else {
179	CFArrayAppendValue(array, trusted_app);
180	CFRelease(trusted_app);
181    }
182
183    /* SystemUIServer */
184    status = SecTrustedApplicationCreateFromPath(kSystemUIServerPath,
185						 &trusted_app);
186    if (status != noErr) {
187	fprintf(stderr,
188		"SecTrustedApplicationCreateFromPath(%s) failed, %d\n",
189		kSystemUIServerPath,
190		(int)status);
191    }
192    else {
193	CFArrayAppendValue(array, trusted_app);
194	CFRelease(trusted_app);
195    }
196
197 done:
198    if (CFArrayGetCount(array) == 0) {
199	my_CFRelease(&array);
200    }
201    return (array);
202}
203
204OSStatus
205EAPOLClientSetACLForIdentity(SecIdentityRef identity)
206{
207    SecKeyRef		private_key = NULL;
208    CFArrayRef		trusted_apps = NULL;
209    OSStatus		status;
210
211    status = SecIdentityCopyPrivateKey(identity, &private_key);
212    if (status != noErr) {
213	goto done;
214    }
215    trusted_apps = copy_trusted_applications(TRUE);
216    if (trusted_apps == NULL) {
217	status = errSecParam;
218	goto done;
219    }
220    status
221	= EAPSecKeychainItemSetAccessForTrustedApplications((SecKeychainItemRef)
222							    private_key,
223							    trusted_apps);
224 done:
225    my_CFRelease(&private_key);
226    my_CFRelease(&trusted_apps);
227    return (status);
228}
229
230STATIC CFDataRef
231itemID_copy_data(EAPOLClientItemIDRef itemID)
232{
233    CFDataRef		data;
234    CFDictionaryRef	dict;
235
236    dict = EAPOLClientItemIDCopyDictionary(itemID);
237    data = CFPropertyListCreateData(NULL, dict,
238				    kCFPropertyListBinaryFormat_v1_0,
239				    0, NULL);
240    if (dict != NULL) {
241        CFRelease(dict);
242    }
243    return (data);
244}
245
246STATIC mach_port_t
247eapolcfg_auth_server_port(void)
248{
249    kern_return_t	kret;
250    mach_port_t		server;
251
252#ifdef BOOTSTRAP_PRIVILEGED_SERVER
253    kret = bootstrap_look_up2(bootstrap_port,
254			      EAPOLCFG_AUTH_SERVER,
255			      &server,
256			      0,
257			      BOOTSTRAP_PRIVILEGED_SERVER);
258
259#else /* BOOTSTRAP_PRIVILEGED_SERVER */
260    kret = bootstrap_look_up(bootstrap_port, EAPOLCFG_AUTH_SERVER, server_p);
261
262#endif /* BOOTSTRAP_PRIVILEGED_SERVER */
263
264    if (kret != BOOTSTRAP_SUCCESS) {
265	/* just to make sure */
266	server = MACH_PORT_NULL;
267	EAPLOG(LOG_NOTICE, "EAPOLClientItemID: can't lookup eapolcfg_auth");
268    }
269    return (server);
270}
271
272/**
273 ** interface to eapolcfg_auth MiG routines
274 **/
275STATIC Boolean
276authEAPOLClientItemIDSetIdentity(EAPOLClientItemIDRef itemID,
277				 SecIdentityRef identity)
278{
279    AuthorizationExternalForm *	auth_ext_p;
280    CFDataRef			id_data = NULL;
281    OOBData_t			id_handle;
282    mach_msg_type_number_t	id_handle_length;
283    CFDataRef			itemID_data = NULL;
284    kern_return_t 		kret;
285    int				result = ENXIO;
286    mach_port_t			server;
287
288    server = eapolcfg_auth_server_port();
289    if (server == MACH_PORT_NULL) {
290	return (FALSE);
291    }
292    auth_ext_p = EAPOLClientItemIDGetAuthorizationExternalForm(itemID);
293    if (identity != NULL) {
294	id_data = EAPSecIdentityHandleCreate(identity);
295	if (id_data == NULL) {
296	    goto done;
297	}
298	id_handle = (OOBData_t)CFDataGetBytePtr(id_data);
299	id_handle_length = CFDataGetLength(id_data);
300    }
301    else {
302	id_handle = NULL;
303	id_handle_length = 0;
304    }
305    itemID_data = itemID_copy_data(itemID);
306    kret = eapolclientitemid_set_identity(server,
307					  auth_ext_p->bytes,
308					  sizeof(auth_ext_p->bytes),
309					  (xmlData_t)
310					  CFDataGetBytePtr(itemID_data),
311					  CFDataGetLength(itemID_data),
312					  id_handle,
313					  id_handle_length,
314					  &result);
315    if (kret != KERN_SUCCESS) {
316	EAPLOG(LOG_ERR, "eapolclientitemid_set_identity failed %d",
317	       kret);
318    }
319    if (result != 0) {
320	EAPLOG(LOG_NOTICE, "eapolclientitemid_set_identity() returned %d",
321	       result);
322    }
323 done:
324    my_CFRelease(&itemID_data);
325    my_CFRelease(&id_data);
326    return (result == 0);
327}
328
329STATIC Boolean
330authEAPOLClientItemIDSetPasswordItem(EAPOLClientItemIDRef itemID,
331				     CFDataRef name_data,
332				     CFDataRef password_data)
333{
334    AuthorizationExternalForm *	auth_ext_p;
335    CFDataRef			itemID_data;
336    uint32_t			flags = 0;
337    kern_return_t 		kret;
338    OOBData_t			name;
339    mach_msg_type_number_t	name_length;
340    OOBData_t			password;
341    mach_msg_type_number_t	password_length;
342    int				result = ENXIO;
343    mach_port_t			server;
344
345    server = eapolcfg_auth_server_port();
346    if (server == MACH_PORT_NULL) {
347	return (FALSE);
348    }
349    auth_ext_p = EAPOLClientItemIDGetAuthorizationExternalForm(itemID);
350    if (name_data != NULL) {
351	flags |= keapolcfg_auth_set_name;
352	name = (OOBData_t)CFDataGetBytePtr(name_data);
353	name_length = CFDataGetLength(name_data);
354    }
355    else {
356	name = NULL;
357	name_length = 0;
358    }
359    if (password_data != NULL) {
360	flags |= keapolcfg_auth_set_password;
361	password = (OOBData_t)CFDataGetBytePtr(password_data);
362	password_length = CFDataGetLength(password_data);
363    }
364    else {
365	password = NULL;
366	password_length = 0;
367    }
368    itemID_data = itemID_copy_data(itemID);
369    kret = eapolclientitemid_set_password(server,
370					  auth_ext_p->bytes,
371					  sizeof(auth_ext_p->bytes),
372					  (xmlData_t)
373					  CFDataGetBytePtr(itemID_data),
374					  CFDataGetLength(itemID_data),
375					  flags,
376					  name, name_length,
377					  password, password_length,
378					  &result);
379    if (kret != KERN_SUCCESS) {
380	EAPLOG(LOG_ERR, "eapolclientitemid_set_password failed %d",
381	       kret);
382    }
383    if (result != 0) {
384	EAPLOG(LOG_NOTICE, "eapolclientitemid_set_password() returned %d",
385	       result);
386    }
387    my_CFRelease(&itemID_data);
388    return (result == 0);
389}
390
391STATIC Boolean
392authEAPOLClientItemIDRemovePasswordItem(EAPOLClientItemIDRef itemID)
393{
394    AuthorizationExternalForm *	auth_ext_p;
395    CFDataRef			itemID_data;
396    kern_return_t 		kret;
397    int				result = ENXIO;
398    mach_port_t			server;
399
400    server = eapolcfg_auth_server_port();
401    if (server == MACH_PORT_NULL) {
402	return (FALSE);
403    }
404    auth_ext_p = EAPOLClientItemIDGetAuthorizationExternalForm(itemID);
405    itemID_data = itemID_copy_data(itemID);
406    kret = eapolclientitemid_remove_password(server,
407					     auth_ext_p->bytes,
408					     sizeof(auth_ext_p->bytes),
409					     (xmlData_t)
410					     CFDataGetBytePtr(itemID_data),
411					     CFDataGetLength(itemID_data),
412					     &result);
413    if (kret != KERN_SUCCESS) {
414	EAPLOG(LOG_ERR, "eapolclientitemid_remove_password failed %d",
415	       kret);
416    }
417    if (result != 0) {
418	EAPLOG(LOG_DEBUG, "eapolclientitemid_remove_password() returned %d",
419	       result);
420    }
421    my_CFRelease(&itemID_data);
422    return (result == 0);
423}
424
425STATIC Boolean
426authEAPOLClientItemIDCopyPasswordItem(EAPOLClientItemIDRef itemID,
427				      CFDataRef * name_data_p,
428				      CFDataRef * password_data_p)
429{
430    AuthorizationExternalForm *	auth_ext_p;
431    CFDataRef			itemID_data;
432    kern_return_t 		kret;
433    OOBDataOut_t		name = NULL;
434    mach_msg_type_number_t	name_length = 0;
435    boolean_t			password_set = FALSE;
436    int				result = ENXIO;
437    mach_port_t			server;
438
439    server = eapolcfg_auth_server_port();
440    if (server == MACH_PORT_NULL) {
441	return (FALSE);
442    }
443    auth_ext_p = EAPOLClientItemIDGetAuthorizationExternalForm(itemID);
444    itemID_data = itemID_copy_data(itemID);
445    kret = eapolclientitemid_check_password(server,
446					    auth_ext_p->bytes,
447					    sizeof(auth_ext_p->bytes),
448					    (xmlData_t)
449					    CFDataGetBytePtr(itemID_data),
450					    CFDataGetLength(itemID_data),
451					    &name, &name_length,
452					    &password_set,
453					    &result);
454    if (kret != KERN_SUCCESS) {
455	EAPLOG(LOG_ERR, "eapolclientitemid_check_password failed %d",
456	       kret);
457    }
458    if (result != 0) {
459	EAPLOG(LOG_DEBUG, "eapolclientitemid_check_password() returned %d",
460	       result);
461    }
462
463    if (name_data_p != NULL) {
464	if (name == NULL) {
465	    *name_data_p = NULL;
466	}
467	else {
468	    *name_data_p = CFDataCreate(NULL, (const UInt8 *)name,
469					name_length);
470	}
471    }
472    if (password_data_p != NULL) {
473	if (password_set == FALSE) {
474	    *password_data_p = NULL;
475	}
476	else {
477	    /* don't return the actual password, return a fake password */
478#define FAKE_PASSWORD		"XXXXXXXX"
479#define FAKE_PASSWORD_LENGTH	(sizeof(FAKE_PASSWORD) - 1)
480	    *password_data_p = CFDataCreate(NULL,
481					    (const UInt8 *)FAKE_PASSWORD,
482					    FAKE_PASSWORD_LENGTH);
483	}
484    }
485    if (name != NULL) {
486	(void)vm_deallocate(mach_task_self(), (vm_address_t)name,
487			    name_length);
488    }
489    my_CFRelease(&itemID_data);
490    return (result == 0);
491}
492
493/**
494 ** EAPOLClientItemIDCopyUniqueString
495 ** - get the unique string for the itemID
496 **/
497
498/* for password/name Item */
499#define WLAN_SSID_STR	"wlan.ssid"
500#define WLAN_DOMAIN_STR	"wlan.domain"
501#define PROFILEID_STR	"profileid"
502#define DEFAULT_STR	"default"
503
504STATIC const char	kItemDescription[] = "802.1X Password";
505STATIC int		kItemDescriptionLength = sizeof(kItemDescription) - 1;
506
507#define EAP_PREFIX_STR	"com.apple.network.eap.%s.%s.%s"
508
509INLINE CFStringRef
510create_item_format(const char * domain, const char * type, const char * unique,
511		   CFStringRef value)
512{
513    CFStringRef		str;
514
515    if (value != NULL) {
516	str = CFStringCreateWithFormat(NULL, NULL,
517				       CFSTR(EAP_PREFIX_STR ".%@"),
518				       domain, type, unique, value);
519    }
520    else {
521	str = CFStringCreateWithFormat(NULL, NULL,
522				       CFSTR(EAP_PREFIX_STR),
523				       domain, type, unique);
524    }
525    return (str);
526}
527
528STATIC CFStringRef
529EAPOLClientItemIDCopyUniqueString(EAPOLClientItemIDRef itemID,
530				  EAPOLClientDomain domain, bool is_item)
531{
532    const char *	domain_str;
533    CFStringRef		result = NULL;
534    CFStringRef		profileID;
535    CFDataRef		ssid;
536    CFStringRef		ssid_str;
537    const char *	type_str;
538
539    type_str = is_item ? "item" : "identity";
540    domain_str = (domain == kEAPOLClientDomainSystem) ? "system" : "user";
541    switch (itemID->type) {
542    case kEAPOLClientItemIDTypeWLANSSID:
543	ssid_str = my_CFStringCreateWithData(itemID->u.ssid);
544	result = create_item_format(domain_str, type_str, WLAN_SSID_STR,
545				    ssid_str);
546	if (ssid_str != NULL) {
547	    CFRelease(ssid_str);
548	}
549	break;
550    case kEAPOLClientItemIDTypeWLANDomain:
551	result = create_item_format(domain_str, type_str,
552				    WLAN_DOMAIN_STR, itemID->u.domain);
553	break;
554    case kEAPOLClientItemIDTypeProfileID:
555	result = create_item_format(domain_str, type_str, PROFILEID_STR,
556				    itemID->u.profileID);
557	break;
558    case kEAPOLClientItemIDTypeProfile:
559	ssid = EAPOLClientProfileGetWLANSSIDAndSecurityType(itemID->u.profile,
560							    NULL);
561	if (ssid != NULL) {
562	    ssid_str = my_CFStringCreateWithData(ssid);
563	    result = create_item_format(domain_str, type_str, WLAN_SSID_STR,
564					ssid_str);
565	    if (ssid_str != NULL) {
566		CFRelease(ssid_str);
567	    }
568	}
569	else {
570	    CFStringRef		wlan_domain;
571
572	    wlan_domain = EAPOLClientProfileGetWLANDomain(itemID->u.profile);
573	    if (wlan_domain != NULL) {
574		result = create_item_format(domain_str, type_str,
575					    WLAN_DOMAIN_STR, wlan_domain);
576	    }
577	    else {
578		profileID = EAPOLClientProfileGetID(itemID->u.profile);
579		result = create_item_format(domain_str, type_str, PROFILEID_STR,
580					    profileID);
581	    }
582	}
583	break;
584    case kEAPOLClientItemIDTypeDefault:
585	result = create_item_format(domain_str, type_str, DEFAULT_STR, NULL);
586	break;
587    default:
588	break;
589    }
590    return (result);
591}
592
593/**
594 ** CF object glue code
595 **/
596STATIC CFStringRef	__EAPOLClientItemIDCopyDebugDesc(CFTypeRef cf);
597STATIC void		__EAPOLClientItemIDDeallocate(CFTypeRef cf);
598STATIC Boolean		__EAPOLClientItemIDEqual(CFTypeRef cf1, CFTypeRef cf2);
599STATIC CFHashCode	__EAPOLClientItemIDHash(CFTypeRef cf);
600
601STATIC CFTypeID __kEAPOLClientItemIDTypeID = _kCFRuntimeNotATypeID;
602
603STATIC const CFRuntimeClass __EAPOLClientItemIDClass = {
604    0,					/* version */
605    "EAPOLClientItemID",		/* className */
606    NULL,				/* init */
607    NULL,				/* copy */
608    __EAPOLClientItemIDDeallocate,	/* deallocate */
609    __EAPOLClientItemIDEqual,		/* equal */
610    __EAPOLClientItemIDHash,		/* hash */
611    NULL,				/* copyFormattingDesc */
612    __EAPOLClientItemIDCopyDebugDesc	/* copyDebugDesc */
613};
614
615STATIC CFStringRef
616__EAPOLClientItemIDCopyDebugDesc(CFTypeRef cf)
617{
618    CFAllocatorRef		allocator = CFGetAllocator(cf);
619    EAPOLClientItemIDRef	itemID = (EAPOLClientItemIDRef)cf;
620    CFStringRef			profileID;
621    CFMutableStringRef		result;
622    CFStringRef			ssid_str;
623
624    result = CFStringCreateMutable(allocator, 0);
625    CFStringAppendFormat(result, NULL,
626			 CFSTR("<EAPOLClientItemID %p [%p]> {"), cf, allocator);
627    switch (itemID->type) {
628    case kEAPOLClientItemIDTypeWLANSSID:
629	ssid_str = my_CFStringCreateWithData(itemID->u.ssid);
630	CFStringAppendFormat(result, NULL, CFSTR("WLAN SSID = %@"),
631			     ssid_str);
632	CFRelease(ssid_str);
633	break;
634    case kEAPOLClientItemIDTypeWLANDomain:
635	CFStringAppendFormat(result, NULL, CFSTR("WLAN domain = %@"),
636			     itemID->u.domain);
637	break;
638    case kEAPOLClientItemIDTypeProfileID:
639	CFStringAppendFormat(result, NULL, CFSTR("ProfileID = %@"),
640			     itemID->u.profileID);
641	break;
642    case kEAPOLClientItemIDTypeProfile:
643	profileID = EAPOLClientProfileGetID(itemID->u.profile);
644	CFStringAppendFormat(result, NULL, CFSTR("Profile = %@"),
645			     profileID);
646	break;
647    case kEAPOLClientItemIDTypeDefault:
648	CFStringAppend(result, CFSTR("Default"));
649	break;
650    default:
651	break;
652    }
653    CFStringAppend(result, CFSTR("}"));
654    return result;
655}
656
657
658STATIC void
659__EAPOLClientItemIDDeallocate(CFTypeRef cf)
660{
661    EAPOLClientItemIDRef itemID	= (EAPOLClientItemIDRef)cf;
662
663    switch (itemID->type) {
664    case kEAPOLClientItemIDTypeWLANSSID:
665	CFRelease(itemID->u.ssid);
666	break;
667    case kEAPOLClientItemIDTypeWLANDomain:
668	CFRelease(itemID->u.domain);
669	break;
670    case kEAPOLClientItemIDTypeProfileID:
671	CFRelease(itemID->u.profileID);
672	break;
673    case kEAPOLClientItemIDTypeProfile:
674	CFRelease(itemID->u.profile);
675	break;
676    default:
677	break;
678    }
679    return;
680}
681
682
683STATIC Boolean
684__EAPOLClientItemIDEqual(CFTypeRef cf1, CFTypeRef cf2)
685{
686    EAPOLClientItemIDRef 	id1 = (EAPOLClientItemIDRef)cf1;
687    EAPOLClientItemIDRef	id2 = (EAPOLClientItemIDRef)cf2;
688
689    if (id1->type != id2->type) {
690	return (FALSE);
691    }
692    return (CFEqual(id1->u.ptr, id2->u.ptr));
693}
694
695STATIC CFHashCode
696__EAPOLClientItemIDHash(CFTypeRef cf)
697{
698    EAPOLClientItemIDRef 	itemID = (EAPOLClientItemIDRef)cf;
699
700    return (CFHash(itemID->u.ptr));
701}
702
703
704STATIC void
705__EAPOLClientItemIDInitialize(void)
706{
707    /* initialize runtime */
708    __kEAPOLClientItemIDTypeID
709	= _CFRuntimeRegisterClass(&__EAPOLClientItemIDClass);
710    return;
711}
712
713STATIC void
714__EAPOLClientItemIDRegisterClass(void)
715{
716    STATIC pthread_once_t	initialized = PTHREAD_ONCE_INIT;
717
718    pthread_once(&initialized, __EAPOLClientItemIDInitialize);
719    return;
720}
721
722
723STATIC EAPOLClientItemIDRef
724__EAPOLClientItemIDAllocate(CFAllocatorRef allocator)
725{
726    EAPOLClientItemIDRef	itemID;
727
728    __EAPOLClientItemIDRegisterClass();
729
730    itemID = (EAPOLClientItemIDRef)
731	_CFRuntimeCreateInstance(allocator,
732				 __kEAPOLClientItemIDTypeID,
733				 sizeof(*itemID) - sizeof(CFRuntimeBase),
734				 NULL);
735    return (itemID);
736}
737
738/**
739 ** EAPOLClientItemID APIs
740 **/
741
742CFTypeID
743EAPOLClientItemIDGetTypeID(void)
744{
745    __EAPOLClientItemIDRegisterClass();
746    return (__kEAPOLClientItemIDTypeID);
747}
748
749/*
750 * Function: EAPOLClientItemIDCreateWithProfileID
751 *
752 * Purpose:
753 *   Create an EAPOLClientItemID instance based on the supplied profileID
754 */
755EAPOLClientItemIDRef
756EAPOLClientItemIDCreateWithProfileID(CFStringRef profileID)
757{
758    EAPOLClientItemIDRef	itemID;
759
760    itemID = __EAPOLClientItemIDAllocate(CFGetAllocator(profileID));
761    if (itemID == NULL) {
762	return (NULL);
763    }
764    itemID->type = kEAPOLClientItemIDTypeProfileID;
765    itemID->u.profileID = CFRetain(profileID);
766    return (itemID);
767}
768
769/*
770 * Function: EAPOLClientItemIDCreateWithWLANSSID
771 *
772 * Purpose:
773 *   Create an EAPOLClientItemID instance based on the supplied WLAN SSID.
774 */
775EAPOLClientItemIDRef
776EAPOLClientItemIDCreateWithWLANSSID(CFDataRef ssid)
777{
778    EAPOLClientItemIDRef	itemID;
779
780    itemID = __EAPOLClientItemIDAllocate(CFGetAllocator(ssid));
781    if (itemID == NULL) {
782	return (NULL);
783    }
784    itemID->type = kEAPOLClientItemIDTypeWLANSSID;
785    itemID->u.ssid = CFRetain(ssid);
786    return (itemID);
787}
788
789/*
790 * Function: EAPOLClientItemIDCreateWithWLANDomain
791 *
792 * Purpose:
793 *   Create an EAPOLClientItemID instance based on the supplied WLAN
794 *   Hotspot 2.0 domain name.
795 */
796EAPOLClientItemIDRef
797EAPOLClientItemIDCreateWithWLANDomain(CFStringRef domain)
798{
799    EAPOLClientItemIDRef	itemID;
800
801    itemID = __EAPOLClientItemIDAllocate(CFGetAllocator(domain));
802    if (itemID == NULL) {
803	return (NULL);
804    }
805    itemID->type = kEAPOLClientItemIDTypeWLANDomain;
806    itemID->u.domain = CFRetain(domain);
807    return (itemID);
808}
809
810/*
811 * Function: EAPOLClientItemIDCreateWithProfile
812 *
813 * Purpose:
814 *   Create an EAPOLClientItemID instance based on the supplied
815 *   EAPOLClientProfileRef.
816 */
817EAPOLClientItemIDRef
818EAPOLClientItemIDCreateWithProfile(EAPOLClientProfileRef profile)
819{
820    EAPOLClientItemIDRef	itemID;
821
822    itemID = __EAPOLClientItemIDAllocate(CFGetAllocator(profile));
823    if (itemID == NULL) {
824	return (NULL);
825    }
826    itemID->type = kEAPOLClientItemIDTypeProfile;
827    CFRetain(profile);
828    itemID->u.profile = profile;
829    return (itemID);
830}
831
832/*
833 * Function: EAPOLClientItemIDCreateDefault
834 *
835 * Purpose:
836 *   Create an EAPOLClientItemID instance that indicates that the default
837 *   authentication parameters and default keychain items are to be used.
838 */
839EAPOLClientItemIDRef
840EAPOLClientItemIDCreateDefault(void)
841{
842    EAPOLClientItemIDRef	itemID;
843
844    itemID = __EAPOLClientItemIDAllocate(NULL);
845    if (itemID == NULL) {
846	return (NULL);
847    }
848    itemID->type = kEAPOLClientItemIDTypeDefault;
849    return (itemID);
850}
851
852/*
853 * Function: EAPOLClientItemIDCopyPasswordItem
854 *
855 * Purpose:
856 *   Retrieve the password item from secure storage for the particular itemID
857 *   in the specified domain.
858 *
859 * Returns:
860 *   FALSE if no such item exists, and both *username_p and *password_p
861 *   are set to NULL.
862 *
863 *   TRUE if an item exists, and either of both *username_p and *password_p
864 *   are set to a non-NULL value.
865 */
866Boolean
867EAPOLClientItemIDCopyPasswordItem(EAPOLClientItemIDRef itemID,
868				  EAPOLClientDomain domain,
869				  CFDataRef * username_p,
870				  CFDataRef * password_p)
871{
872    CFDictionaryRef	attrs = NULL;
873    int			count;
874    SecKeychainRef	keychain = NULL;
875    const void *	keys[2];
876    CFArrayRef		req_props = NULL;
877    OSStatus		status = errSecParam;
878    CFStringRef		unique_string;
879
880    count = 0;
881    if (username_p == NULL && password_p == NULL) {
882	return (FALSE);
883    }
884    switch (domain) {
885    case kEAPOLClientDomainUser:
886	break;
887    case kEAPOLClientDomainSystem:
888	if (EAPOLClientItemIDGetAuthorizationExternalForm(itemID) != NULL) {
889	    return (authEAPOLClientItemIDCopyPasswordItem(itemID, username_p,
890							  password_p));
891	}
892	status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem,
893					      &keychain);
894	if (status != noErr) {
895	    fprintf(stderr, "EAPOLClientItemIDCopyPasswordItem can't get"
896		    " System keychain\n");
897	    return (FALSE);
898	}
899	break;
900    default:
901	return (FALSE);
902    }
903    if (username_p != NULL) {
904	keys[count] = kEAPSecKeychainPropAccount;
905	count++;
906	*username_p = NULL;
907    }
908    if (password_p != NULL) {
909	keys[count] = kEAPSecKeychainPropPassword;
910	count++;
911	*password_p = NULL;
912    }
913    req_props = CFArrayCreate(NULL, keys, count,
914			      &kCFTypeArrayCallBacks);
915    unique_string = EAPOLClientItemIDCopyUniqueString(itemID, domain, TRUE);
916    status = EAPSecKeychainPasswordItemCopy2(keychain,
917					     unique_string,
918					     req_props,
919					     &attrs);
920    if (status != noErr) {
921	goto done;
922    }
923    if (username_p != NULL) {
924	*username_p
925	    = my_CFDictionaryCopyValue(attrs, kEAPSecKeychainPropAccount);
926    }
927    if (password_p != NULL) {
928	*password_p
929	    = my_CFDictionaryCopyValue(attrs, kEAPSecKeychainPropPassword);
930
931    }
932
933 done:
934    my_CFRelease(&unique_string);
935    my_CFRelease(&req_props);
936    my_CFRelease(&attrs);
937    my_CFRelease(&keychain);
938    return (status == noErr);
939}
940
941/*
942 * Function: EAPOLClientItemIDSetPasswordItem
943 *
944 * Purpose:
945 *   Set the password item in secure storage for the specified itemID
946 *   in the specified domain.
947 *
948 *   Passing an empty 'username' or 'password' removes the corresponding
949 *   attribute.   If both 'username' and 'password' are empty, the item is
950 *   also removed.  An empty value is a non-NULL CFDataRef of length 0.
951 *
952 *   Passing NULL for 'username' or 'password' means that the corresponding
953 *   item attribute is left alone.  If both 'username" and 'password' are
954 *   NULL, the call has no effect, but TRUE is still returned.
955 *
956 *   Passing non-NULL, non-empty 'username' or 'password' sets the
957 *   corresponding item attribute to the specified value.   If the item
958 *   does not exist, it will be created.
959 *
960 * Returns:
961 *   FALSE if the operation did not succeed, TRUE otherwise.
962 */
963Boolean
964EAPOLClientItemIDSetPasswordItem(EAPOLClientItemIDRef itemID,
965				 EAPOLClientDomain domain,
966				 CFDataRef name, CFDataRef password)
967{
968    CFMutableDictionaryRef	attrs = NULL;
969    CFDataRef			data;
970    SecKeychainRef		keychain = NULL;
971    CFDataRef			ssid;
972    OSStatus			status = errSecParam;
973    CFStringRef			unique_string;
974
975    if (name == NULL && password == NULL) {
976	return (TRUE);
977    }
978    switch (domain) {
979    case kEAPOLClientDomainUser:
980	break;
981    case kEAPOLClientDomainSystem:
982	if (EAPOLClientItemIDGetAuthorizationExternalForm(itemID) != NULL) {
983	    return (authEAPOLClientItemIDSetPasswordItem(itemID, name,
984							 password));
985	}
986	status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem,
987					      &keychain);
988	if (status != noErr) {
989	    fprintf(stderr, "EAPOLClientItemIDSetPasswordItem can't get"
990		    " System keychain,  %s (%d)\n",
991		    EAPSecurityErrorString(status), (int)status);
992	    return (FALSE);
993	}
994	break;
995    default:
996	return (FALSE);
997    }
998
999    /* populate an attributes dictionary */
1000    attrs = CFDictionaryCreateMutable(NULL, 0,
1001				      &kCFTypeDictionaryKeyCallBacks,
1002				      &kCFTypeDictionaryValueCallBacks);
1003
1004    /* Description */
1005    data = CFDataCreate(NULL, (UInt8 *)kItemDescription,
1006			kItemDescriptionLength);
1007    CFDictionarySetValue(attrs, kEAPSecKeychainPropDescription, data);
1008    CFRelease(data);
1009
1010    /* Label */
1011    switch (itemID->type) {
1012    case kEAPOLClientItemIDTypeWLANSSID:
1013	CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel,
1014			     itemID->u.ssid);
1015	break;
1016    case kEAPOLClientItemIDTypeWLANDomain: {
1017	CFDataRef		label_data;
1018
1019	label_data = my_CFDataCreateWithString(itemID->u.domain);
1020	CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel,
1021			     label_data);
1022	CFRelease(label_data);
1023	break;
1024    }
1025    case kEAPOLClientItemIDTypeProfileID: {
1026	CFDataRef		label_data;
1027
1028	label_data = my_CFDataCreateWithString(itemID->u.profileID);
1029	CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel, label_data);
1030	CFRelease(label_data);
1031	break;
1032    }
1033    case kEAPOLClientItemIDTypeProfile:
1034	ssid = EAPOLClientProfileGetWLANSSIDAndSecurityType(itemID->u.profile,
1035							    NULL);
1036	if (ssid != NULL) {
1037	    CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel,
1038				 ssid);
1039	}
1040	else {
1041	    CFStringRef		label;
1042	    CFDataRef		label_data;
1043
1044	    label = EAPOLClientProfileGetUserDefinedName(itemID->u.profile);
1045	    if (label == NULL) {
1046		label = EAPOLClientProfileGetWLANDomain(itemID->u.profile);
1047		if (label == NULL) {
1048		    label = EAPOLClientProfileGetID(itemID->u.profile);
1049		}
1050	    }
1051	    label_data = my_CFDataCreateWithString(label);
1052	    CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel, label_data);
1053	    CFRelease(label_data);
1054	}
1055	break;
1056    case kEAPOLClientItemIDTypeDefault: {
1057	CFDataRef		label_data;
1058
1059	/* XXX localize? */
1060	label_data = my_CFDataCreateWithString(CFSTR("Default"));
1061	CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel, label_data);
1062	CFRelease(label_data);
1063	break;
1064    }
1065    default:
1066	goto done;
1067    }
1068
1069    /* Account */
1070    if (name != NULL) {
1071	CFDictionarySetValue(attrs, kEAPSecKeychainPropAccount, name);
1072    }
1073
1074    /* Password */
1075    if (password != NULL) {
1076	CFDictionarySetValue(attrs, kEAPSecKeychainPropPassword, password);
1077    };
1078
1079    if (domain == kEAPOLClientDomainUser) {
1080	CFArrayRef			trusted_apps;
1081
1082	/* Trusted Applications */
1083	trusted_apps = copy_trusted_applications(FALSE);
1084	if (trusted_apps != NULL) {
1085	    CFDictionarySetValue(attrs,
1086				 kEAPSecKeychainPropTrustedApplications,
1087				 trusted_apps);
1088	    CFRelease(trusted_apps);
1089	}
1090    }
1091    else {
1092	CFDictionarySetValue(attrs,
1093			     kEAPSecKeychainPropAllowRootAccess,
1094			     kCFBooleanTrue);
1095    }
1096    unique_string = EAPOLClientItemIDCopyUniqueString(itemID, domain, TRUE);
1097    status = EAPSecKeychainPasswordItemSet2(keychain, unique_string,
1098					    attrs);
1099    if (status == errSecItemNotFound) {
1100	status = EAPSecKeychainPasswordItemCreate(keychain,
1101						  unique_string,
1102						  attrs);
1103    }
1104    my_CFRelease(&unique_string);
1105    if (status != noErr) {
1106	EAPLOG(LOG_NOTICE,
1107	       "EAPOLClientItemID: failed to set keychain item, %d",
1108	       (int)status);
1109    }
1110
1111 done:
1112    my_CFRelease(&attrs);
1113    my_CFRelease(&keychain);
1114    return (status == noErr);
1115}
1116
1117/*
1118 * Function: EAPOLClientItemIDRemovePasswordItem
1119 *
1120 * Purpose:
1121 *   Remove the password item in secure storage for the specified itemID
1122 *   in the specified domain.
1123 *
1124 * Returns:
1125 *   FALSE if the operation did not succeed, TRUE otherwise.
1126 */
1127Boolean
1128EAPOLClientItemIDRemovePasswordItem(EAPOLClientItemIDRef itemID,
1129				    EAPOLClientDomain domain)
1130{
1131    SecKeychainRef		keychain = NULL;
1132    OSStatus			status = errSecParam;
1133    CFStringRef			unique_string;
1134
1135    switch (domain) {
1136    case kEAPOLClientDomainUser:
1137	break;
1138    case kEAPOLClientDomainSystem:
1139	if (EAPOLClientItemIDGetAuthorizationExternalForm(itemID) != NULL) {
1140	    return (authEAPOLClientItemIDRemovePasswordItem(itemID));
1141	}
1142	status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem,
1143					      &keychain);
1144	if (status != noErr) {
1145	    fprintf(stderr, "EAPOLClientItemIDRemovePasswordItem can't get"
1146		    " System keychain,  %s (%d)\n",
1147		    EAPSecurityErrorString(status), (int)status);
1148	    return (FALSE);
1149	}
1150	break;
1151    default:
1152	return (FALSE);
1153    }
1154    unique_string = EAPOLClientItemIDCopyUniqueString(itemID, domain, TRUE);
1155    status = EAPSecKeychainPasswordItemRemove(keychain,
1156					      unique_string);
1157    my_CFRelease(&unique_string);
1158    my_CFRelease(&keychain);
1159    return (status == noErr);
1160}
1161
1162/*
1163 * Function: EAPOLClientItemIDCopyIdentity
1164 *
1165 * Purpose:
1166 *   Retrieve the identity associated with the particular itemID
1167 *   in the specified domain.
1168 *
1169 * Returns:
1170 *   non-NULL SecIdentityRef when match can be found for the item ID,
1171 *   NULL otherwise.
1172 */
1173SecIdentityRef
1174EAPOLClientItemIDCopyIdentity(EAPOLClientItemIDRef itemID,
1175			      EAPOLClientDomain domain)
1176{
1177    SecPreferencesDomain 	current_domain;
1178    SecIdentityRef		identity = NULL;
1179    SecPreferencesDomain 	required_domain;
1180    OSStatus			status;
1181    CFStringRef			unique_string;
1182
1183    switch (domain) {
1184    case kEAPOLClientDomainUser:
1185	required_domain = kSecPreferencesDomainUser;
1186	break;
1187    case kEAPOLClientDomainSystem:
1188	required_domain = kSecPreferencesDomainSystem;
1189	break;
1190    default:
1191	return (NULL);
1192    }
1193    status = SecKeychainGetPreferenceDomain(&current_domain);
1194    if (status != noErr) {
1195	return (NULL);
1196    }
1197    if (current_domain != required_domain) {
1198	status = SecKeychainSetPreferenceDomain(required_domain);
1199	if (status != noErr) {
1200	    return (NULL);
1201	}
1202    }
1203    unique_string = EAPOLClientItemIDCopyUniqueString(itemID, domain, FALSE);
1204    identity = SecIdentityCopyPreferred(unique_string, NULL, NULL);
1205    if (current_domain != required_domain) {
1206	(void)SecKeychainSetPreferenceDomain(current_domain);
1207    }
1208    my_CFRelease(&unique_string);
1209    return (identity);
1210}
1211
1212/*
1213 * Function: EAPOLClientItemIDSetIdentity
1214 *
1215 * Purpose:
1216 *   Associate an identity with the specified itemID in the specified
1217 *   domain.
1218 *
1219 *   If the identity is NULL, the identity preference is removed.
1220 *
1221 * Returns:
1222 *   FALSE if the operation did not succeed, TRUE otherwise.
1223 */
1224Boolean
1225EAPOLClientItemIDSetIdentity(EAPOLClientItemIDRef itemID,
1226			     EAPOLClientDomain domain,
1227			     SecIdentityRef identity)
1228{
1229    SecPreferencesDomain 	current_domain;
1230    SecPreferencesDomain 	required_domain;
1231    OSStatus			status;
1232    CFStringRef			unique_string;
1233
1234    switch (domain) {
1235    case kEAPOLClientDomainUser:
1236	required_domain = kSecPreferencesDomainUser;
1237	break;
1238    case kEAPOLClientDomainSystem:
1239	if (EAPOLClientItemIDGetAuthorizationExternalForm(itemID) != NULL) {
1240	    return (authEAPOLClientItemIDSetIdentity(itemID, identity));
1241	}
1242	required_domain = kSecPreferencesDomainSystem;
1243	break;
1244    default:
1245	return (FALSE);
1246    }
1247
1248    status = SecKeychainGetPreferenceDomain(&current_domain);
1249    if (status != noErr) {
1250	return (FALSE);
1251    }
1252    if (required_domain != current_domain) {
1253	status = SecKeychainSetPreferenceDomain(required_domain);
1254	if (status != noErr) {
1255	    return (FALSE);
1256	}
1257    }
1258    unique_string = EAPOLClientItemIDCopyUniqueString(itemID, domain, FALSE);
1259    status = SecIdentitySetPreferred(identity, unique_string, NULL);
1260    if (status != noErr) {
1261	fprintf(stderr, "SecIdentitySetPreference failed %s (%d)\n",
1262		EAPSecurityErrorString(status), (int)status);
1263    }
1264
1265    if (current_domain != required_domain) {
1266	(void)SecKeychainSetPreferenceDomain(current_domain);
1267    }
1268    my_CFRelease(&unique_string);
1269    return (status == noErr);
1270}
1271
1272/**
1273 ** Private functions
1274 **/
1275
1276
1277CFStringRef
1278EAPOLClientItemIDGetProfileID(EAPOLClientItemIDRef itemID)
1279{
1280    switch (itemID->type) {
1281    case kEAPOLClientItemIDTypeProfileID:
1282	return (itemID->u.profileID);
1283    case kEAPOLClientItemIDTypeProfile:
1284	return (EAPOLClientProfileGetID(itemID->u.profile));
1285    default:
1286	break;
1287    }
1288    return (NULL);
1289}
1290
1291CFDataRef
1292EAPOLClientItemIDGetWLANSSID(EAPOLClientItemIDRef itemID)
1293{
1294    switch (itemID->type) {
1295    case kEAPOLClientItemIDTypeWLANSSID:
1296	return (itemID->u.ssid);
1297    case kEAPOLClientItemIDTypeProfile:
1298	return (EAPOLClientProfileGetWLANSSIDAndSecurityType(itemID->u.profile,
1299							     NULL));
1300    default:
1301	break;
1302    }
1303    return (NULL);
1304}
1305
1306CFStringRef
1307EAPOLClientItemIDGetWLANDomain(EAPOLClientItemIDRef itemID)
1308{
1309    switch (itemID->type) {
1310    case kEAPOLClientItemIDTypeWLANDomain:
1311	return (itemID->u.domain);
1312    case kEAPOLClientItemIDTypeProfile:
1313	return (EAPOLClientProfileGetWLANDomain(itemID->u.profile));
1314    default:
1315	break;
1316    }
1317    return (NULL);
1318}
1319
1320EAPOLClientProfileRef
1321EAPOLClientItemIDGetProfile(EAPOLClientItemIDRef itemID)
1322{
1323    switch (itemID->type) {
1324    case kEAPOLClientItemIDTypeProfile:
1325	return (itemID->u.profile);
1326    default:
1327	break;
1328    }
1329    return (NULL);
1330}
1331
1332#define kItemProfileID		CFSTR("ProfileID")
1333#define kItemDomain		CFSTR("Domain")
1334#define kItemSSID		CFSTR("SSID")
1335#define kItemDefault		CFSTR("Default")
1336
1337CFDictionaryRef
1338EAPOLClientItemIDCopyDictionary(EAPOLClientItemIDRef itemID)
1339{
1340    const void *	key;
1341    CFStringRef		profileID;
1342    const void *	value;
1343
1344    profileID = EAPOLClientItemIDGetProfileID(itemID);
1345    if (profileID != NULL) {
1346	key = (const void *)kItemProfileID;
1347	value = (const void *)profileID;
1348    }
1349    else {
1350	CFDataRef		ssid = EAPOLClientItemIDGetWLANSSID(itemID);
1351
1352	if (ssid != NULL) {
1353	    key = (const void *)kItemSSID;
1354	    value = (const void *)ssid;
1355	}
1356	else {
1357	    switch (itemID->type) {
1358	    case kEAPOLClientItemIDTypeWLANDomain:
1359		key = (const void *)kItemDomain;
1360		value = (const void *)itemID->u.domain;
1361		break;
1362	    case kEAPOLClientItemIDTypeDefault:
1363		key = (const void *)kItemDefault;
1364		value = (const void *)kCFBooleanTrue;
1365		break;
1366	    default:
1367		return (NULL);
1368	    }
1369	}
1370    }
1371    return (CFDictionaryCreate(NULL, &key, &value, 1,
1372			       &kCFTypeDictionaryKeyCallBacks,
1373			       &kCFTypeDictionaryValueCallBacks));
1374}
1375
1376EAPOLClientItemIDRef
1377EAPOLClientItemIDCreateWithDictionary(EAPOLClientConfigurationRef cfg,
1378				      CFDictionaryRef dict)
1379{
1380    CFStringRef			domain;
1381    EAPOLClientProfileRef	profile;
1382    CFStringRef			profileID;
1383    CFDataRef			ssid;
1384
1385    if (isA_CFDictionary(dict) == NULL) {
1386	return (NULL);
1387    }
1388    profileID = CFDictionaryGetValue(dict, kItemProfileID);
1389    if (isA_CFString(profileID) != NULL) {
1390	if (cfg != NULL) {
1391	    profile = EAPOLClientConfigurationGetProfileWithID(cfg, profileID);
1392	    if (profile != NULL) {
1393		return (EAPOLClientItemIDCreateWithProfile(profile));
1394	    }
1395	}
1396	return (EAPOLClientItemIDCreateWithProfileID(profileID));
1397    }
1398    ssid = CFDictionaryGetValue(dict, kItemSSID);
1399    if (isA_CFData(ssid) != NULL) {
1400	if (cfg != NULL) {
1401	    profile = EAPOLClientConfigurationGetProfileWithWLANSSID(cfg, ssid);
1402	    if (profile != NULL) {
1403		return (EAPOLClientItemIDCreateWithProfile(profile));
1404	    }
1405	}
1406	return (EAPOLClientItemIDCreateWithWLANSSID(ssid));
1407    }
1408    domain = CFDictionaryGetValue(dict, kItemDomain);
1409    if (isA_CFString(domain) != NULL) {
1410	if (cfg != NULL) {
1411	    profile
1412		= EAPOLClientConfigurationGetProfileWithWLANDomain(cfg,
1413								   domain);
1414	    if (profile != NULL) {
1415		return (EAPOLClientItemIDCreateWithProfile(profile));
1416	    }
1417	}
1418	return (EAPOLClientItemIDCreateWithWLANDomain(domain));
1419    }
1420    if (CFDictionaryGetValue(dict, kItemDefault) != NULL) {
1421	return (EAPOLClientItemIDCreateDefault());
1422    }
1423    return (NULL);
1424}
1425
1426PRIVATE_EXTERN AuthorizationExternalForm *
1427EAPOLClientItemIDGetAuthorizationExternalForm(EAPOLClientItemIDRef itemID)
1428{
1429    EAPOLClientConfigurationRef	cfg;
1430    EAPOLClientProfileRef	profile;
1431
1432    profile = EAPOLClientItemIDGetProfile(itemID);
1433    if (profile == NULL) {
1434	return (NULL);
1435    }
1436    cfg = EAPOLClientProfileGetConfiguration(profile);
1437    if (cfg == NULL) {
1438	return (NULL);
1439    }
1440    return (EAPOLClientConfigurationGetAuthorizationExternalForm(cfg));
1441}
1442