1/*
2 * Copyright (c) 2009-2013 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 = CFPropertyListCreateXMLData(NULL, dict);
238    if (dict != NULL) {
239        CFRelease(dict);
240    }
241    return (data);
242}
243
244STATIC mach_port_t
245eapolcfg_auth_server_port(void)
246{
247    kern_return_t	kret;
248    mach_port_t		server;
249
250#ifdef BOOTSTRAP_PRIVILEGED_SERVER
251    kret = bootstrap_look_up2(bootstrap_port,
252			      EAPOLCFG_AUTH_SERVER,
253			      &server,
254			      0,
255			      BOOTSTRAP_PRIVILEGED_SERVER);
256
257#else /* BOOTSTRAP_PRIVILEGED_SERVER */
258    kret = bootstrap_look_up(bootstrap_port, EAPOLCFG_AUTH_SERVER, server_p);
259
260#endif /* BOOTSTRAP_PRIVILEGED_SERVER */
261
262    if (kret != BOOTSTRAP_SUCCESS) {
263	/* just to make sure */
264	server = MACH_PORT_NULL;
265	EAPLOG(LOG_NOTICE, "EAPOLClientItemID: can't lookup eapolcfg_auth");
266    }
267    return (server);
268}
269
270/**
271 ** interface to eapolcfg_auth MiG routines
272 **/
273STATIC Boolean
274authEAPOLClientItemIDSetIdentity(EAPOLClientItemIDRef itemID,
275				 SecIdentityRef identity)
276{
277    AuthorizationExternalForm *	auth_ext_p;
278    CFDataRef			id_data = NULL;
279    OOBData_t			id_handle;
280    mach_msg_type_number_t	id_handle_length;
281    CFDataRef			itemID_data = NULL;
282    kern_return_t 		kret;
283    int				result = ENXIO;
284    mach_port_t			server;
285
286    server = eapolcfg_auth_server_port();
287    if (server == MACH_PORT_NULL) {
288	return (FALSE);
289    }
290    auth_ext_p = EAPOLClientItemIDGetAuthorizationExternalForm(itemID);
291    if (identity != NULL) {
292	id_data = EAPSecIdentityHandleCreate(identity);
293	if (id_data == NULL) {
294	    goto done;
295	}
296	id_handle = (OOBData_t)CFDataGetBytePtr(id_data);
297	id_handle_length = CFDataGetLength(id_data);
298    }
299    else {
300	id_handle = NULL;
301	id_handle_length = 0;
302    }
303    itemID_data = itemID_copy_data(itemID);
304    kret = eapolclientitemid_set_identity(server,
305					  auth_ext_p->bytes,
306					  sizeof(auth_ext_p->bytes),
307					  (xmlData_t)
308					  CFDataGetBytePtr(itemID_data),
309					  CFDataGetLength(itemID_data),
310					  id_handle,
311					  id_handle_length,
312					  &result);
313    if (kret != KERN_SUCCESS) {
314	EAPLOG(LOG_ERR, "eapolclientitemid_set_identity failed %d",
315	       kret);
316    }
317    if (result != 0) {
318	EAPLOG(LOG_NOTICE, "eapolclientitemid_set_identity() returned %d",
319	       result);
320    }
321 done:
322    my_CFRelease(&itemID_data);
323    my_CFRelease(&id_data);
324    return (result == 0);
325}
326
327STATIC Boolean
328authEAPOLClientItemIDSetPasswordItem(EAPOLClientItemIDRef itemID,
329				     CFDataRef name_data,
330				     CFDataRef password_data)
331{
332    AuthorizationExternalForm *	auth_ext_p;
333    CFDataRef			itemID_data;
334    uint32_t			flags = 0;
335    kern_return_t 		kret;
336    OOBData_t			name;
337    mach_msg_type_number_t	name_length;
338    OOBData_t			password;
339    mach_msg_type_number_t	password_length;
340    int				result = ENXIO;
341    mach_port_t			server;
342
343    server = eapolcfg_auth_server_port();
344    if (server == MACH_PORT_NULL) {
345	return (FALSE);
346    }
347    auth_ext_p = EAPOLClientItemIDGetAuthorizationExternalForm(itemID);
348    if (name_data != NULL) {
349	flags |= keapolcfg_auth_set_name;
350	name = (OOBData_t)CFDataGetBytePtr(name_data);
351	name_length = CFDataGetLength(name_data);
352    }
353    else {
354	name = NULL;
355	name_length = 0;
356    }
357    if (password_data != NULL) {
358	flags |= keapolcfg_auth_set_password;
359	password = (OOBData_t)CFDataGetBytePtr(password_data);
360	password_length = CFDataGetLength(password_data);
361    }
362    else {
363	password = NULL;
364	password_length = 0;
365    }
366    itemID_data = itemID_copy_data(itemID);
367    kret = eapolclientitemid_set_password(server,
368					  auth_ext_p->bytes,
369					  sizeof(auth_ext_p->bytes),
370					  (xmlData_t)
371					  CFDataGetBytePtr(itemID_data),
372					  CFDataGetLength(itemID_data),
373					  flags,
374					  name, name_length,
375					  password, password_length,
376					  &result);
377    if (kret != KERN_SUCCESS) {
378	EAPLOG(LOG_ERR, "eapolclientitemid_set_password failed %d",
379	       kret);
380    }
381    if (result != 0) {
382	EAPLOG(LOG_NOTICE, "eapolclientitemid_set_password() returned %d",
383	       result);
384    }
385    my_CFRelease(&itemID_data);
386    return (result == 0);
387}
388
389STATIC Boolean
390authEAPOLClientItemIDRemovePasswordItem(EAPOLClientItemIDRef itemID)
391{
392    AuthorizationExternalForm *	auth_ext_p;
393    CFDataRef			itemID_data;
394    kern_return_t 		kret;
395    int				result = ENXIO;
396    mach_port_t			server;
397
398    server = eapolcfg_auth_server_port();
399    if (server == MACH_PORT_NULL) {
400	return (FALSE);
401    }
402    auth_ext_p = EAPOLClientItemIDGetAuthorizationExternalForm(itemID);
403    itemID_data = itemID_copy_data(itemID);
404    kret = eapolclientitemid_remove_password(server,
405					     auth_ext_p->bytes,
406					     sizeof(auth_ext_p->bytes),
407					     (xmlData_t)
408					     CFDataGetBytePtr(itemID_data),
409					     CFDataGetLength(itemID_data),
410					     &result);
411    if (kret != KERN_SUCCESS) {
412	EAPLOG(LOG_ERR, "eapolclientitemid_remove_password failed %d",
413	       kret);
414    }
415    if (result != 0) {
416	EAPLOG(LOG_DEBUG, "eapolclientitemid_remove_password() returned %d",
417	       result);
418    }
419    my_CFRelease(&itemID_data);
420    return (result == 0);
421}
422
423STATIC Boolean
424authEAPOLClientItemIDCopyPasswordItem(EAPOLClientItemIDRef itemID,
425				      CFDataRef * name_data_p,
426				      CFDataRef * password_data_p)
427{
428    AuthorizationExternalForm *	auth_ext_p;
429    CFDataRef			itemID_data;
430    kern_return_t 		kret;
431    OOBDataOut_t		name = NULL;
432    mach_msg_type_number_t	name_length = 0;
433    boolean_t			password_set = FALSE;
434    int				result = ENXIO;
435    mach_port_t			server;
436
437    server = eapolcfg_auth_server_port();
438    if (server == MACH_PORT_NULL) {
439	return (FALSE);
440    }
441    auth_ext_p = EAPOLClientItemIDGetAuthorizationExternalForm(itemID);
442    itemID_data = itemID_copy_data(itemID);
443    kret = eapolclientitemid_check_password(server,
444					    auth_ext_p->bytes,
445					    sizeof(auth_ext_p->bytes),
446					    (xmlData_t)
447					    CFDataGetBytePtr(itemID_data),
448					    CFDataGetLength(itemID_data),
449					    &name, &name_length,
450					    &password_set,
451					    &result);
452    if (kret != KERN_SUCCESS) {
453	EAPLOG(LOG_ERR, "eapolclientitemid_check_password failed %d",
454	       kret);
455    }
456    if (result != 0) {
457	EAPLOG(LOG_DEBUG, "eapolclientitemid_check_password() returned %d",
458	       result);
459    }
460
461    if (name_data_p != NULL) {
462	if (name == NULL) {
463	    *name_data_p = NULL;
464	}
465	else {
466	    *name_data_p = CFDataCreate(NULL, (const UInt8 *)name,
467					name_length);
468	}
469    }
470    if (password_data_p != NULL) {
471	if (password_set == FALSE) {
472	    *password_data_p = NULL;
473	}
474	else {
475	    /* don't return the actual password, return a fake password */
476#define FAKE_PASSWORD		"XXXXXXXX"
477#define FAKE_PASSWORD_LENGTH	(sizeof(FAKE_PASSWORD) - 1)
478	    *password_data_p = CFDataCreate(NULL,
479					    (const UInt8 *)FAKE_PASSWORD,
480					    FAKE_PASSWORD_LENGTH);
481	}
482    }
483    if (name != NULL) {
484	(void)vm_deallocate(mach_task_self(), (vm_address_t)name,
485			    name_length);
486    }
487    my_CFRelease(&itemID_data);
488    return (result == 0);
489}
490
491/**
492 ** EAPOLClientItemIDCopyUniqueString
493 ** - get the unique string for the itemID
494 **/
495
496/* for password/name Item */
497#define WLAN_SSID_STR	"wlan.ssid"
498#define WLAN_DOMAIN_STR	"wlan.domain"
499#define PROFILEID_STR	"profileid"
500#define DEFAULT_STR	"default"
501
502STATIC const char	kItemDescription[] = "802.1X Password";
503STATIC int		kItemDescriptionLength = sizeof(kItemDescription) - 1;
504
505#define EAP_PREFIX_STR	"com.apple.network.eap.%s.%s.%s"
506
507INLINE CFStringRef
508create_item_format(const char * domain, const char * type, const char * unique,
509		   CFStringRef value)
510{
511    CFStringRef		str;
512
513    if (value != NULL) {
514	str = CFStringCreateWithFormat(NULL, NULL,
515				       CFSTR(EAP_PREFIX_STR ".%@"),
516				       domain, type, unique, value);
517    }
518    else {
519	str = CFStringCreateWithFormat(NULL, NULL,
520				       CFSTR(EAP_PREFIX_STR),
521				       domain, type, unique);
522    }
523    return (str);
524}
525
526STATIC CFStringRef
527EAPOLClientItemIDCopyUniqueString(EAPOLClientItemIDRef itemID,
528				  EAPOLClientDomain domain, bool is_item)
529{
530    const char *	domain_str;
531    CFStringRef		result = NULL;
532    CFStringRef		profileID;
533    CFDataRef		ssid;
534    CFStringRef		ssid_str;
535    const char *	type_str;
536
537    type_str = is_item ? "item" : "identity";
538    domain_str = (domain == kEAPOLClientDomainSystem) ? "system" : "user";
539    switch (itemID->type) {
540    case kEAPOLClientItemIDTypeWLANSSID:
541	ssid_str = my_CFStringCreateWithData(itemID->u.ssid);
542	result = create_item_format(domain_str, type_str, WLAN_SSID_STR,
543				    ssid_str);
544	if (ssid_str != NULL) {
545	    CFRelease(ssid_str);
546	}
547	break;
548    case kEAPOLClientItemIDTypeWLANDomain:
549	result = create_item_format(domain_str, type_str,
550				    WLAN_DOMAIN_STR, itemID->u.domain);
551	break;
552    case kEAPOLClientItemIDTypeProfileID:
553	result = create_item_format(domain_str, type_str, PROFILEID_STR,
554				    itemID->u.profileID);
555	break;
556    case kEAPOLClientItemIDTypeProfile:
557	ssid = EAPOLClientProfileGetWLANSSIDAndSecurityType(itemID->u.profile,
558							    NULL);
559	if (ssid != NULL) {
560	    ssid_str = my_CFStringCreateWithData(ssid);
561	    result = create_item_format(domain_str, type_str, WLAN_SSID_STR,
562					ssid_str);
563	    if (ssid_str != NULL) {
564		CFRelease(ssid_str);
565	    }
566	}
567	else {
568	    CFStringRef		wlan_domain;
569
570	    wlan_domain = EAPOLClientProfileGetWLANDomain(itemID->u.profile);
571	    if (wlan_domain != NULL) {
572		result = create_item_format(domain_str, type_str,
573					    WLAN_DOMAIN_STR, wlan_domain);
574	    }
575	    else {
576		profileID = EAPOLClientProfileGetID(itemID->u.profile);
577		result = create_item_format(domain_str, type_str, PROFILEID_STR,
578					    profileID);
579	    }
580	}
581	break;
582    case kEAPOLClientItemIDTypeDefault:
583	result = create_item_format(domain_str, type_str, DEFAULT_STR, NULL);
584	break;
585    default:
586	break;
587    }
588    return (result);
589}
590
591/**
592 ** CF object glue code
593 **/
594STATIC CFStringRef	__EAPOLClientItemIDCopyDebugDesc(CFTypeRef cf);
595STATIC void		__EAPOLClientItemIDDeallocate(CFTypeRef cf);
596STATIC Boolean		__EAPOLClientItemIDEqual(CFTypeRef cf1, CFTypeRef cf2);
597STATIC CFHashCode	__EAPOLClientItemIDHash(CFTypeRef cf);
598
599STATIC CFTypeID __kEAPOLClientItemIDTypeID = _kCFRuntimeNotATypeID;
600
601STATIC const CFRuntimeClass __EAPOLClientItemIDClass = {
602    0,					/* version */
603    "EAPOLClientItemID",		/* className */
604    NULL,				/* init */
605    NULL,				/* copy */
606    __EAPOLClientItemIDDeallocate,	/* deallocate */
607    __EAPOLClientItemIDEqual,		/* equal */
608    __EAPOLClientItemIDHash,		/* hash */
609    NULL,				/* copyFormattingDesc */
610    __EAPOLClientItemIDCopyDebugDesc	/* copyDebugDesc */
611};
612
613STATIC CFStringRef
614__EAPOLClientItemIDCopyDebugDesc(CFTypeRef cf)
615{
616    CFAllocatorRef		allocator = CFGetAllocator(cf);
617    EAPOLClientItemIDRef	itemID = (EAPOLClientItemIDRef)cf;
618    CFStringRef			profileID;
619    CFMutableStringRef		result;
620    CFStringRef			ssid_str;
621
622    result = CFStringCreateMutable(allocator, 0);
623    CFStringAppendFormat(result, NULL,
624			 CFSTR("<EAPOLClientItemID %p [%p]> {"), cf, allocator);
625    switch (itemID->type) {
626    case kEAPOLClientItemIDTypeWLANSSID:
627	ssid_str = my_CFStringCreateWithData(itemID->u.ssid);
628	CFStringAppendFormat(result, NULL, CFSTR("WLAN SSID = %@"),
629			     ssid_str);
630	CFRelease(ssid_str);
631	break;
632    case kEAPOLClientItemIDTypeWLANDomain:
633	CFStringAppendFormat(result, NULL, CFSTR("WLAN domain = %@"),
634			     itemID->u.domain);
635	break;
636    case kEAPOLClientItemIDTypeProfileID:
637	CFStringAppendFormat(result, NULL, CFSTR("ProfileID = %@"),
638			     itemID->u.profileID);
639	break;
640    case kEAPOLClientItemIDTypeProfile:
641	profileID = EAPOLClientProfileGetID(itemID->u.profile);
642	CFStringAppendFormat(result, NULL, CFSTR("Profile = %@"),
643			     profileID);
644	break;
645    case kEAPOLClientItemIDTypeDefault:
646	CFStringAppend(result, CFSTR("Default"));
647	break;
648    default:
649	break;
650    }
651    CFStringAppend(result, CFSTR("}"));
652    return result;
653}
654
655
656STATIC void
657__EAPOLClientItemIDDeallocate(CFTypeRef cf)
658{
659    EAPOLClientItemIDRef itemID	= (EAPOLClientItemIDRef)cf;
660
661    switch (itemID->type) {
662    case kEAPOLClientItemIDTypeWLANSSID:
663	CFRelease(itemID->u.ssid);
664	break;
665    case kEAPOLClientItemIDTypeWLANDomain:
666	CFRelease(itemID->u.domain);
667	break;
668    case kEAPOLClientItemIDTypeProfileID:
669	CFRelease(itemID->u.profileID);
670	break;
671    case kEAPOLClientItemIDTypeProfile:
672	CFRelease(itemID->u.profile);
673	break;
674    default:
675	break;
676    }
677    return;
678}
679
680
681STATIC Boolean
682__EAPOLClientItemIDEqual(CFTypeRef cf1, CFTypeRef cf2)
683{
684    EAPOLClientItemIDRef 	id1 = (EAPOLClientItemIDRef)cf1;
685    EAPOLClientItemIDRef	id2 = (EAPOLClientItemIDRef)cf2;
686
687    if (id1->type != id2->type) {
688	return (FALSE);
689    }
690    return (CFEqual(id1->u.ptr, id2->u.ptr));
691}
692
693STATIC CFHashCode
694__EAPOLClientItemIDHash(CFTypeRef cf)
695{
696    EAPOLClientItemIDRef 	itemID = (EAPOLClientItemIDRef)cf;
697
698    return (CFHash(itemID->u.ptr));
699}
700
701
702STATIC void
703__EAPOLClientItemIDInitialize(void)
704{
705    /* initialize runtime */
706    __kEAPOLClientItemIDTypeID
707	= _CFRuntimeRegisterClass(&__EAPOLClientItemIDClass);
708    return;
709}
710
711STATIC void
712__EAPOLClientItemIDRegisterClass(void)
713{
714    STATIC pthread_once_t	initialized = PTHREAD_ONCE_INIT;
715
716    pthread_once(&initialized, __EAPOLClientItemIDInitialize);
717    return;
718}
719
720
721STATIC EAPOLClientItemIDRef
722__EAPOLClientItemIDAllocate(CFAllocatorRef allocator)
723{
724    EAPOLClientItemIDRef	itemID;
725
726    __EAPOLClientItemIDRegisterClass();
727
728    itemID = (EAPOLClientItemIDRef)
729	_CFRuntimeCreateInstance(allocator,
730				 __kEAPOLClientItemIDTypeID,
731				 sizeof(*itemID) - sizeof(CFRuntimeBase),
732				 NULL);
733    return (itemID);
734}
735
736/**
737 ** EAPOLClientItemID APIs
738 **/
739
740CFTypeID
741EAPOLClientItemIDGetTypeID(void)
742{
743    __EAPOLClientItemIDRegisterClass();
744    return (__kEAPOLClientItemIDTypeID);
745}
746
747/*
748 * Function: EAPOLClientItemIDCreateWithProfileID
749 *
750 * Purpose:
751 *   Create an EAPOLClientItemID instance based on the supplied profileID
752 */
753EAPOLClientItemIDRef
754EAPOLClientItemIDCreateWithProfileID(CFStringRef profileID)
755{
756    EAPOLClientItemIDRef	itemID;
757
758    itemID = __EAPOLClientItemIDAllocate(CFGetAllocator(profileID));
759    if (itemID == NULL) {
760	return (NULL);
761    }
762    itemID->type = kEAPOLClientItemIDTypeProfileID;
763    itemID->u.profileID = CFRetain(profileID);
764    return (itemID);
765}
766
767/*
768 * Function: EAPOLClientItemIDCreateWithWLANSSID
769 *
770 * Purpose:
771 *   Create an EAPOLClientItemID instance based on the supplied WLAN SSID.
772 */
773EAPOLClientItemIDRef
774EAPOLClientItemIDCreateWithWLANSSID(CFDataRef ssid)
775{
776    EAPOLClientItemIDRef	itemID;
777
778    itemID = __EAPOLClientItemIDAllocate(CFGetAllocator(ssid));
779    if (itemID == NULL) {
780	return (NULL);
781    }
782    itemID->type = kEAPOLClientItemIDTypeWLANSSID;
783    itemID->u.ssid = CFRetain(ssid);
784    return (itemID);
785}
786
787/*
788 * Function: EAPOLClientItemIDCreateWithWLANDomain
789 *
790 * Purpose:
791 *   Create an EAPOLClientItemID instance based on the supplied WLAN
792 *   Hotspot 2.0 domain name.
793 */
794EAPOLClientItemIDRef
795EAPOLClientItemIDCreateWithWLANDomain(CFStringRef domain)
796{
797    EAPOLClientItemIDRef	itemID;
798
799    itemID = __EAPOLClientItemIDAllocate(CFGetAllocator(domain));
800    if (itemID == NULL) {
801	return (NULL);
802    }
803    itemID->type = kEAPOLClientItemIDTypeWLANDomain;
804    itemID->u.domain = CFRetain(domain);
805    return (itemID);
806}
807
808/*
809 * Function: EAPOLClientItemIDCreateWithProfile
810 *
811 * Purpose:
812 *   Create an EAPOLClientItemID instance based on the supplied
813 *   EAPOLClientProfileRef.
814 */
815EAPOLClientItemIDRef
816EAPOLClientItemIDCreateWithProfile(EAPOLClientProfileRef profile)
817{
818    EAPOLClientItemIDRef	itemID;
819
820    itemID = __EAPOLClientItemIDAllocate(CFGetAllocator(profile));
821    if (itemID == NULL) {
822	return (NULL);
823    }
824    itemID->type = kEAPOLClientItemIDTypeProfile;
825    CFRetain(profile);
826    itemID->u.profile = profile;
827    return (itemID);
828}
829
830/*
831 * Function: EAPOLClientItemIDCreateDefault
832 *
833 * Purpose:
834 *   Create an EAPOLClientItemID instance that indicates that the default
835 *   authentication parameters and default keychain items are to be used.
836 */
837EAPOLClientItemIDRef
838EAPOLClientItemIDCreateDefault(void)
839{
840    EAPOLClientItemIDRef	itemID;
841
842    itemID = __EAPOLClientItemIDAllocate(NULL);
843    if (itemID == NULL) {
844	return (NULL);
845    }
846    itemID->type = kEAPOLClientItemIDTypeDefault;
847    return (itemID);
848}
849
850/*
851 * Function: EAPOLClientItemIDCopyPasswordItem
852 *
853 * Purpose:
854 *   Retrieve the password item from secure storage for the particular itemID
855 *   in the specified domain.
856 *
857 * Returns:
858 *   FALSE if no such item exists, and both *username_p and *password_p
859 *   are set to NULL.
860 *
861 *   TRUE if an item exists, and either of both *username_p and *password_p
862 *   are set to a non-NULL value.
863 */
864Boolean
865EAPOLClientItemIDCopyPasswordItem(EAPOLClientItemIDRef itemID,
866				  EAPOLClientDomain domain,
867				  CFDataRef * username_p,
868				  CFDataRef * password_p)
869{
870    CFDictionaryRef	attrs = NULL;
871    int			count;
872    SecKeychainRef	keychain = NULL;
873    const void *	keys[2];
874    CFArrayRef		req_props = NULL;
875    OSStatus		status = errSecParam;
876    CFStringRef		unique_string;
877
878    count = 0;
879    if (username_p == NULL && password_p == NULL) {
880	return (FALSE);
881    }
882    switch (domain) {
883    case kEAPOLClientDomainUser:
884	status = SecKeychainCopyDomainDefault(kSecPreferencesDomainUser,
885					      &keychain);
886	if (status != noErr) {
887	    fprintf(stderr, "EAPOLClientItemIDCopyPasswordItem can't get"
888		    " User keychain\n");
889	    return (FALSE);
890	}
891	break;
892    case kEAPOLClientDomainSystem:
893	if (EAPOLClientItemIDGetAuthorizationExternalForm(itemID) != NULL) {
894	    return (authEAPOLClientItemIDCopyPasswordItem(itemID, username_p,
895							  password_p));
896	}
897	status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem,
898					      &keychain);
899	if (status != noErr) {
900	    fprintf(stderr, "EAPOLClientItemIDCopyPasswordItem can't get"
901		    " System keychain\n");
902	    return (FALSE);
903	}
904	break;
905    default:
906	return (FALSE);
907    }
908    if (username_p != NULL) {
909	keys[count] = kEAPSecKeychainPropAccount;
910	count++;
911	*username_p = NULL;
912    }
913    if (password_p != NULL) {
914	keys[count] = kEAPSecKeychainPropPassword;
915	count++;
916	*password_p = NULL;
917    }
918    req_props = CFArrayCreate(NULL, keys, count,
919			      &kCFTypeArrayCallBacks);
920    unique_string = EAPOLClientItemIDCopyUniqueString(itemID, domain, TRUE);
921    status = EAPSecKeychainPasswordItemCopy2(keychain,
922					     unique_string,
923					     req_props,
924					     &attrs);
925    if (status != noErr) {
926	goto done;
927    }
928    if (username_p != NULL) {
929	*username_p
930	    = my_CFDictionaryCopyValue(attrs, kEAPSecKeychainPropAccount);
931    }
932    if (password_p != NULL) {
933	*password_p
934	    = my_CFDictionaryCopyValue(attrs, kEAPSecKeychainPropPassword);
935
936    }
937
938 done:
939    my_CFRelease(&unique_string);
940    my_CFRelease(&req_props);
941    my_CFRelease(&attrs);
942    my_CFRelease(&keychain);
943    return (status == noErr);
944}
945
946/*
947 * Function: EAPOLClientItemIDSetPasswordItem
948 *
949 * Purpose:
950 *   Set the password item in secure storage for the specified itemID
951 *   in the specified domain.
952 *
953 *   Passing an empty 'username' or 'password' removes the corresponding
954 *   attribute.   If both 'username' and 'password' are empty, the item is
955 *   also removed.  An empty value is a non-NULL CFDataRef of length 0.
956 *
957 *   Passing NULL for 'username' or 'password' means that the corresponding
958 *   item attribute is left alone.  If both 'username" and 'password' are
959 *   NULL, the call has no effect, but TRUE is still returned.
960 *
961 *   Passing non-NULL, non-empty 'username' or 'password' sets the
962 *   corresponding item attribute to the specified value.   If the item
963 *   does not exist, it will be created.
964 *
965 * Returns:
966 *   FALSE if the operation did not succeed, TRUE otherwise.
967 */
968Boolean
969EAPOLClientItemIDSetPasswordItem(EAPOLClientItemIDRef itemID,
970				 EAPOLClientDomain domain,
971				 CFDataRef name, CFDataRef password)
972{
973    CFMutableDictionaryRef	attrs = NULL;
974    CFDataRef			data;
975    SecKeychainRef		keychain = NULL;
976    CFDataRef			ssid;
977    OSStatus			status = errSecParam;
978    CFStringRef			unique_string;
979
980    if (name == NULL && password == NULL) {
981	return (TRUE);
982    }
983    switch (domain) {
984    case kEAPOLClientDomainUser:
985	status = SecKeychainCopyDomainDefault(kSecPreferencesDomainUser,
986					      &keychain);
987	if (status != noErr) {
988	    fprintf(stderr, "EAPOLClientItemIDSetPasswordItem can't get"
989		    " User keychain,  %s (%d)\n",
990		    EAPSecurityErrorString(status), (int)status);
991	    return (FALSE);
992	}
993	break;
994    case kEAPOLClientDomainSystem:
995	if (EAPOLClientItemIDGetAuthorizationExternalForm(itemID) != NULL) {
996	    return (authEAPOLClientItemIDSetPasswordItem(itemID, name,
997							 password));
998	}
999	status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem,
1000					      &keychain);
1001	if (status != noErr) {
1002	    fprintf(stderr, "EAPOLClientItemIDSetPasswordItem can't get"
1003		    " System keychain,  %s (%d)\n",
1004		    EAPSecurityErrorString(status), (int)status);
1005	    return (FALSE);
1006	}
1007	break;
1008    default:
1009	return (FALSE);
1010    }
1011
1012    /* populate an attributes dictionary */
1013    attrs = CFDictionaryCreateMutable(NULL, 0,
1014				      &kCFTypeDictionaryKeyCallBacks,
1015				      &kCFTypeDictionaryValueCallBacks);
1016
1017    /* Description */
1018    data = CFDataCreate(NULL, (UInt8 *)kItemDescription,
1019			kItemDescriptionLength);
1020    CFDictionarySetValue(attrs, kEAPSecKeychainPropDescription, data);
1021    CFRelease(data);
1022
1023    /* Label */
1024    switch (itemID->type) {
1025    case kEAPOLClientItemIDTypeWLANSSID:
1026	CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel,
1027			     itemID->u.ssid);
1028	break;
1029    case kEAPOLClientItemIDTypeWLANDomain: {
1030	CFDataRef		label_data;
1031
1032	label_data = my_CFDataCreateWithString(itemID->u.domain);
1033	CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel,
1034			     label_data);
1035	CFRelease(label_data);
1036	break;
1037    }
1038    case kEAPOLClientItemIDTypeProfileID: {
1039	CFDataRef		label_data;
1040
1041	label_data = my_CFDataCreateWithString(itemID->u.profileID);
1042	CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel, label_data);
1043	CFRelease(label_data);
1044	break;
1045    }
1046    case kEAPOLClientItemIDTypeProfile:
1047	ssid = EAPOLClientProfileGetWLANSSIDAndSecurityType(itemID->u.profile,
1048							    NULL);
1049	if (ssid != NULL) {
1050	    CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel,
1051				 ssid);
1052	}
1053	else {
1054	    CFStringRef		label;
1055	    CFDataRef		label_data;
1056
1057	    label = EAPOLClientProfileGetUserDefinedName(itemID->u.profile);
1058	    if (label == NULL) {
1059		label = EAPOLClientProfileGetWLANDomain(itemID->u.profile);
1060		if (label == NULL) {
1061		    label = EAPOLClientProfileGetID(itemID->u.profile);
1062		}
1063	    }
1064	    label_data = my_CFDataCreateWithString(label);
1065	    CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel, label_data);
1066	    CFRelease(label_data);
1067	}
1068	break;
1069    case kEAPOLClientItemIDTypeDefault: {
1070	CFDataRef		label_data;
1071
1072	/* XXX localize? */
1073	label_data = my_CFDataCreateWithString(CFSTR("Default"));
1074	CFDictionarySetValue(attrs, kEAPSecKeychainPropLabel, label_data);
1075	CFRelease(label_data);
1076	break;
1077    }
1078    default:
1079	goto done;
1080    }
1081
1082    /* Account */
1083    if (name != NULL) {
1084	CFDictionarySetValue(attrs, kEAPSecKeychainPropAccount, name);
1085    }
1086
1087    /* Password */
1088    if (password != NULL) {
1089	CFDictionarySetValue(attrs, kEAPSecKeychainPropPassword, password);
1090    };
1091
1092    if (domain == kEAPOLClientDomainUser) {
1093	CFArrayRef			trusted_apps;
1094
1095	/* Trusted Applications */
1096	trusted_apps = copy_trusted_applications(FALSE);
1097	if (trusted_apps != NULL) {
1098	    CFDictionarySetValue(attrs,
1099				 kEAPSecKeychainPropTrustedApplications,
1100				 trusted_apps);
1101	    CFRelease(trusted_apps);
1102	}
1103    }
1104    else {
1105	CFDictionarySetValue(attrs,
1106			     kEAPSecKeychainPropAllowRootAccess,
1107			     kCFBooleanTrue);
1108    }
1109    unique_string = EAPOLClientItemIDCopyUniqueString(itemID, domain, TRUE);
1110    status = EAPSecKeychainPasswordItemSet2(keychain, unique_string,
1111					    attrs);
1112    if (status == errSecItemNotFound) {
1113	status = EAPSecKeychainPasswordItemCreate(keychain,
1114						  unique_string,
1115						  attrs);
1116    }
1117    my_CFRelease(&unique_string);
1118    if (status != noErr) {
1119	EAPLOG(LOG_NOTICE,
1120	       "EAPOLClientItemID: failed to set keychain item, %d",
1121	       (int)status);
1122    }
1123
1124 done:
1125    my_CFRelease(&attrs);
1126    my_CFRelease(&keychain);
1127    return (status == noErr);
1128}
1129
1130/*
1131 * Function: EAPOLClientItemIDRemovePasswordItem
1132 *
1133 * Purpose:
1134 *   Remove the password item in secure storage for the specified itemID
1135 *   in the specified domain.
1136 *
1137 * Returns:
1138 *   FALSE if the operation did not succeed, TRUE otherwise.
1139 */
1140Boolean
1141EAPOLClientItemIDRemovePasswordItem(EAPOLClientItemIDRef itemID,
1142				    EAPOLClientDomain domain)
1143{
1144    SecKeychainRef		keychain = NULL;
1145    OSStatus			status = errSecParam;
1146    CFStringRef			unique_string;
1147
1148    switch (domain) {
1149    case kEAPOLClientDomainUser:
1150	status = SecKeychainCopyDomainDefault(kSecPreferencesDomainUser,
1151					      &keychain);
1152	if (status != noErr) {
1153	    fprintf(stderr, "EAPOLClientItemIDSetPasswordItem can't get"
1154		    " User keychain,  %s (%d)\n",
1155		    EAPSecurityErrorString(status), (int)status);
1156	    return (FALSE);
1157	}
1158	break;
1159    case kEAPOLClientDomainSystem:
1160	if (EAPOLClientItemIDGetAuthorizationExternalForm(itemID) != NULL) {
1161	    return (authEAPOLClientItemIDRemovePasswordItem(itemID));
1162	}
1163	status = SecKeychainCopyDomainDefault(kSecPreferencesDomainSystem,
1164					      &keychain);
1165	if (status != noErr) {
1166	    fprintf(stderr, "EAPOLClientItemIDSetPasswordItem can't get"
1167		    " System keychain,  %s (%d)\n",
1168		    EAPSecurityErrorString(status), (int)status);
1169	    return (FALSE);
1170	}
1171	break;
1172    default:
1173	return (FALSE);
1174    }
1175    unique_string = EAPOLClientItemIDCopyUniqueString(itemID, domain, TRUE);
1176    status = EAPSecKeychainPasswordItemRemove(keychain,
1177					      unique_string);
1178    my_CFRelease(&unique_string);
1179    my_CFRelease(&keychain);
1180    return (status == noErr);
1181}
1182
1183/*
1184 * Function: EAPOLClientItemIDCopyIdentity
1185 *
1186 * Purpose:
1187 *   Retrieve the identity associated with the particular itemID
1188 *   in the specified domain.
1189 *
1190 * Returns:
1191 *   non-NULL SecIdentityRef when match can be found for the item ID,
1192 *   NULL otherwise.
1193 */
1194SecIdentityRef
1195EAPOLClientItemIDCopyIdentity(EAPOLClientItemIDRef itemID,
1196			      EAPOLClientDomain domain)
1197{
1198    SecPreferencesDomain 	current_domain;
1199    SecIdentityRef		identity = NULL;
1200    SecPreferencesDomain 	required_domain;
1201    OSStatus			status;
1202    CFStringRef			unique_string;
1203
1204    switch (domain) {
1205    case kEAPOLClientDomainUser:
1206	required_domain = kSecPreferencesDomainUser;
1207	break;
1208    case kEAPOLClientDomainSystem:
1209	required_domain = kSecPreferencesDomainSystem;
1210	break;
1211    default:
1212	return (NULL);
1213    }
1214    status = SecKeychainGetPreferenceDomain(&current_domain);
1215    if (status != noErr) {
1216	return (NULL);
1217    }
1218    if (current_domain != required_domain) {
1219	status = SecKeychainSetPreferenceDomain(required_domain);
1220	if (status != noErr) {
1221	    return (NULL);
1222	}
1223    }
1224    unique_string = EAPOLClientItemIDCopyUniqueString(itemID, domain, FALSE);
1225    identity = SecIdentityCopyPreferred(unique_string, NULL, NULL);
1226    if (current_domain != required_domain) {
1227	(void)SecKeychainSetPreferenceDomain(current_domain);
1228    }
1229    my_CFRelease(&unique_string);
1230    return (identity);
1231}
1232
1233/*
1234 * Function: EAPOLClientItemIDSetIdentity
1235 *
1236 * Purpose:
1237 *   Associate an identity with the specified itemID in the specified
1238 *   domain.
1239 *
1240 *   If the identity is NULL, the identity preference is removed.
1241 *
1242 * Returns:
1243 *   FALSE if the operation did not succeed, TRUE otherwise.
1244 */
1245Boolean
1246EAPOLClientItemIDSetIdentity(EAPOLClientItemIDRef itemID,
1247			     EAPOLClientDomain domain,
1248			     SecIdentityRef identity)
1249{
1250    SecPreferencesDomain 	current_domain;
1251    SecPreferencesDomain 	required_domain;
1252    OSStatus			status;
1253    CFStringRef			unique_string;
1254
1255    switch (domain) {
1256    case kEAPOLClientDomainUser:
1257	required_domain = kSecPreferencesDomainUser;
1258	break;
1259    case kEAPOLClientDomainSystem:
1260	if (EAPOLClientItemIDGetAuthorizationExternalForm(itemID) != NULL) {
1261	    return (authEAPOLClientItemIDSetIdentity(itemID, identity));
1262	}
1263	required_domain = kSecPreferencesDomainSystem;
1264	break;
1265    default:
1266	return (FALSE);
1267    }
1268
1269    status = SecKeychainGetPreferenceDomain(&current_domain);
1270    if (status != noErr) {
1271	return (FALSE);
1272    }
1273    if (required_domain != current_domain) {
1274	status = SecKeychainSetPreferenceDomain(required_domain);
1275	if (status != noErr) {
1276	    return (FALSE);
1277	}
1278    }
1279    unique_string = EAPOLClientItemIDCopyUniqueString(itemID, domain, FALSE);
1280    status = SecIdentitySetPreferred(identity, unique_string, NULL);
1281    if (status != noErr) {
1282	fprintf(stderr, "SecIdentitySetPreference failed %s (%d)\n",
1283		EAPSecurityErrorString(status), (int)status);
1284    }
1285
1286    if (current_domain != required_domain) {
1287	(void)SecKeychainSetPreferenceDomain(current_domain);
1288    }
1289    my_CFRelease(&unique_string);
1290    return (status == noErr);
1291}
1292
1293/**
1294 ** Private functions
1295 **/
1296
1297
1298CFStringRef
1299EAPOLClientItemIDGetProfileID(EAPOLClientItemIDRef itemID)
1300{
1301    switch (itemID->type) {
1302    case kEAPOLClientItemIDTypeProfileID:
1303	return (itemID->u.profileID);
1304    case kEAPOLClientItemIDTypeProfile:
1305	return (EAPOLClientProfileGetID(itemID->u.profile));
1306    default:
1307	break;
1308    }
1309    return (NULL);
1310}
1311
1312CFDataRef
1313EAPOLClientItemIDGetWLANSSID(EAPOLClientItemIDRef itemID)
1314{
1315    switch (itemID->type) {
1316    case kEAPOLClientItemIDTypeWLANSSID:
1317	return (itemID->u.ssid);
1318    case kEAPOLClientItemIDTypeProfile:
1319	return (EAPOLClientProfileGetWLANSSIDAndSecurityType(itemID->u.profile,
1320							     NULL));
1321    default:
1322	break;
1323    }
1324    return (NULL);
1325}
1326
1327CFStringRef
1328EAPOLClientItemIDGetWLANDomain(EAPOLClientItemIDRef itemID)
1329{
1330    switch (itemID->type) {
1331    case kEAPOLClientItemIDTypeWLANDomain:
1332	return (itemID->u.domain);
1333    case kEAPOLClientItemIDTypeProfile:
1334	return (EAPOLClientProfileGetWLANDomain(itemID->u.profile));
1335    default:
1336	break;
1337    }
1338    return (NULL);
1339}
1340
1341EAPOLClientProfileRef
1342EAPOLClientItemIDGetProfile(EAPOLClientItemIDRef itemID)
1343{
1344    switch (itemID->type) {
1345    case kEAPOLClientItemIDTypeProfile:
1346	return (itemID->u.profile);
1347    default:
1348	break;
1349    }
1350    return (NULL);
1351}
1352
1353#define kItemProfileID		CFSTR("ProfileID")
1354#define kItemDomain		CFSTR("Domain")
1355#define kItemSSID		CFSTR("SSID")
1356#define kItemDefault		CFSTR("Default")
1357
1358CFDictionaryRef
1359EAPOLClientItemIDCopyDictionary(EAPOLClientItemIDRef itemID)
1360{
1361    const void *	key;
1362    CFStringRef		profileID;
1363    const void *	value;
1364
1365    profileID = EAPOLClientItemIDGetProfileID(itemID);
1366    if (profileID != NULL) {
1367	key = (const void *)kItemProfileID;
1368	value = (const void *)profileID;
1369    }
1370    else {
1371	CFDataRef		ssid = EAPOLClientItemIDGetWLANSSID(itemID);
1372
1373	if (ssid != NULL) {
1374	    key = (const void *)kItemSSID;
1375	    value = (const void *)ssid;
1376	}
1377	else {
1378	    switch (itemID->type) {
1379	    case kEAPOLClientItemIDTypeWLANDomain:
1380		key = (const void *)kItemDomain;
1381		value = (const void *)itemID->u.domain;
1382		break;
1383	    case kEAPOLClientItemIDTypeDefault:
1384		key = (const void *)kItemDefault;
1385		value = (const void *)kCFBooleanTrue;
1386		break;
1387	    default:
1388		return (NULL);
1389	    }
1390	}
1391    }
1392    return (CFDictionaryCreate(NULL, &key, &value, 1,
1393			       &kCFTypeDictionaryKeyCallBacks,
1394			       &kCFTypeDictionaryValueCallBacks));
1395}
1396
1397EAPOLClientItemIDRef
1398EAPOLClientItemIDCreateWithDictionary(EAPOLClientConfigurationRef cfg,
1399				      CFDictionaryRef dict)
1400{
1401    CFStringRef			domain;
1402    EAPOLClientProfileRef	profile;
1403    CFStringRef			profileID;
1404    CFDataRef			ssid;
1405
1406    if (isA_CFDictionary(dict) == NULL) {
1407	return (NULL);
1408    }
1409    profileID = CFDictionaryGetValue(dict, kItemProfileID);
1410    if (isA_CFString(profileID) != NULL) {
1411	if (cfg != NULL) {
1412	    profile = EAPOLClientConfigurationGetProfileWithID(cfg, profileID);
1413	    if (profile != NULL) {
1414		return (EAPOLClientItemIDCreateWithProfile(profile));
1415	    }
1416	}
1417	return (EAPOLClientItemIDCreateWithProfileID(profileID));
1418    }
1419    ssid = CFDictionaryGetValue(dict, kItemSSID);
1420    if (isA_CFData(ssid) != NULL) {
1421	if (cfg != NULL) {
1422	    profile = EAPOLClientConfigurationGetProfileWithWLANSSID(cfg, ssid);
1423	    if (profile != NULL) {
1424		return (EAPOLClientItemIDCreateWithProfile(profile));
1425	    }
1426	}
1427	return (EAPOLClientItemIDCreateWithWLANSSID(ssid));
1428    }
1429    domain = CFDictionaryGetValue(dict, kItemDomain);
1430    if (isA_CFString(domain) != NULL) {
1431	if (cfg != NULL) {
1432	    profile
1433		= EAPOLClientConfigurationGetProfileWithWLANDomain(cfg,
1434								   domain);
1435	    if (profile != NULL) {
1436		return (EAPOLClientItemIDCreateWithProfile(profile));
1437	    }
1438	}
1439	return (EAPOLClientItemIDCreateWithWLANDomain(domain));
1440    }
1441    if (CFDictionaryGetValue(dict, kItemDefault) != NULL) {
1442	return (EAPOLClientItemIDCreateDefault());
1443    }
1444    return (NULL);
1445}
1446
1447PRIVATE_EXTERN AuthorizationExternalForm *
1448EAPOLClientItemIDGetAuthorizationExternalForm(EAPOLClientItemIDRef itemID)
1449{
1450    EAPOLClientConfigurationRef	cfg;
1451    EAPOLClientProfileRef	profile;
1452
1453    profile = EAPOLClientItemIDGetProfile(itemID);
1454    if (profile == NULL) {
1455	return (NULL);
1456    }
1457    cfg = EAPOLClientProfileGetConfiguration(profile);
1458    if (cfg == NULL) {
1459	return (NULL);
1460    }
1461    return (EAPOLClientConfigurationGetAuthorizationExternalForm(cfg));
1462}
1463