1/*
2 * Copyright (c) 2001-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 * Modification History
26 *
27 * November 8, 2001	Dieter Siegmund
28 * - created
29 */
30
31#include <CoreFoundation/CFUserNotification.h>
32#include <CoreFoundation/CFString.h>
33#include <CoreFoundation/CFRunLoop.h>
34#include <SystemConfiguration/SCDPlugin.h>
35#include <SystemConfiguration/SCValidation.h>
36#include <Security/SecCertificateOIDs.h>
37#include "EAPCertificateUtil.h"
38#include <sys/types.h>
39#include <pwd.h>
40#include <sys/wait.h>
41#include <unistd.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <fcntl.h>
45#include <paths.h>
46#include <pthread.h>
47#include <sys/queue.h>
48#include "Dialogue.h"
49#include "mylog.h"
50#include "myCFUtil.h"
51
52/**
53 ** CredentialsDialogue
54 **/
55
56const CFStringRef	kCredentialsDialogueSSID = CFSTR("SSID");
57const CFStringRef	kCredentialsDialogueAccountName = CFSTR("AccountName");
58const CFStringRef	kCredentialsDialoguePassword = CFSTR("Password");
59const CFStringRef	kCredentialsDialogueCertificates = CFSTR("Certificates");
60const CFStringRef	kCredentialsDialogueRememberInformation = CFSTR("RememberInformation");
61const CFStringRef	kCredentialsDialoguePasswordChangeRequired = CFSTR("PasswordChangeRequired");
62
63struct CredentialsDialogue_s;
64#define LIST_HEAD_CredentialsDialogueHead LIST_HEAD(CredentialsDialogueHead, CredentialsDialogue_s)
65static LIST_HEAD_CredentialsDialogueHead  	S_CredentialsDialogueHead;
66static struct CredentialsDialogueHead * S_CredentialsDialogueHead_p = &S_CredentialsDialogueHead;
67
68#define LIST_ENTRY_CredentialsDialogue	LIST_ENTRY(CredentialsDialogue_s)
69
70struct CredentialsDialogue_s {
71    LIST_ENTRY_CredentialsDialogue	entries;
72
73    CredentialsDialogueResponseCallBack func;
74    const void *			arg1;
75    const void *			arg2;
76
77    Boolean				remember_information;
78    CFURLRef				icon_url;
79    CFArrayRef				identity_list; /* of SecIdentityRef's */
80    CFArrayRef				identity_labels;
81    CFURLRef				localization_url;
82    CFStringRef				name;
83    Boolean				name_enabled;
84    CFUserNotificationRef 		notif;
85    CFStringRef				password;
86    Boolean				password_enabled;
87    Boolean				password_change;
88    CFRunLoopSourceRef			rls;
89    CFStringRef				ssid;
90};
91
92#define kEAPOLControllerPath	"/System/Library/SystemConfiguration/EAPOLController.bundle"
93
94/*
95 * Override values for credentials dialogue.  Used by password change
96 * to provide continuity across CFUN invocations, and provide and updated
97 * message to the user.
98 */
99#define kOverrideMessage		CFSTR("Message")
100#define kOverridePassword		CFSTR("Password")
101#define kOverrideNewPassword		CFSTR("NewPassword")
102#define kOverrideNewPasswordAgain	CFSTR("NewPasswordAgain")
103
104static CFUserNotificationRef
105CredentialsDialogueCreateUserNotification(CredentialsDialogueRef dialogue_p,
106					  CFDictionaryRef overrides);
107
108static void
109CredentialsDialogueFreeElements(CredentialsDialogueRef dialogue_p);
110
111static CFBundleRef
112get_bundle(void)
113{
114    static CFBundleRef		bundle = NULL;
115    CFURLRef			url;
116
117    if (bundle != NULL) {
118	return (bundle);
119    }
120    url = CFURLCreateWithFileSystemPath(NULL,
121					CFSTR(kEAPOLControllerPath),
122					kCFURLPOSIXPathStyle, FALSE);
123    if (url != NULL) {
124	bundle = CFBundleCreate(NULL, url);
125	CFRelease(url);
126    }
127    return (bundle);
128}
129
130static CFStringRef
131copy_localized_string(CFBundleRef bundle, CFStringRef ethernet_str,
132		      CFStringRef airport_str, CFTypeRef ssid)
133{
134    CFStringRef		str = NULL;
135
136    if (ssid != NULL) {
137	CFStringRef	format;
138
139	format  = CFBundleCopyLocalizedString(bundle, airport_str, airport_str,
140					      NULL);
141	if (format != NULL) {
142	    str = CFStringCreateWithFormat(NULL, NULL, format, ssid);
143	    CFRelease(format);
144	}
145    }
146    else {
147	str = CFBundleCopyLocalizedString(bundle, ethernet_str, ethernet_str,
148					  NULL);
149    }
150    if (str == NULL) {
151	str = CFRetain(ethernet_str);
152    }
153    return (str);
154}
155
156static CFStringRef
157copy_localized_title(CFBundleRef bundle, CFTypeRef ssid)
158{
159#define kAirPort8021XTitleFormat  CFSTR("Authenticating to network \"%@\"")
160#define kEthernet8021XTitle	  CFSTR("Authenticating to 802.1X network")
161
162    return (copy_localized_string(bundle,
163				  kEthernet8021XTitle,
164				  kAirPort8021XTitleFormat,
165				  ssid));
166}
167
168static CFArrayRef
169copy_certificate_labels(CFArrayRef certs, CFStringRef cert_label,
170			CFArrayRef * ret_identities)
171{
172    CFMutableArrayRef 	cert_labels = NULL;
173    CFMutableArrayRef	certs_filtered = NULL;
174    int			count;
175    int			i;
176    CFRange		r;
177
178    count = CFArrayGetCount(certs);
179    cert_labels = CFArrayCreateMutable(NULL, count + 1, &kCFTypeArrayCallBacks);
180    /* add the first element which is reserved to mean no cert is selected */
181    CFArrayAppendValue(cert_labels, cert_label);
182    r.location = 0;
183    r.length = 1;
184    certs_filtered = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks);
185
186    for (i = 0; i < count; i++) {
187	SecCertificateRef	cert = NULL;
188	SecIdentityRef		identity;
189	CFStringRef		str = NULL;
190
191	identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, i);
192	SecIdentityCopyCertificate(identity, &cert);
193	if (cert != NULL) {
194	    str = SecCertificateCopyShortDescription(NULL, cert, NULL);
195	    CFRelease(cert);
196	}
197	if (str != NULL) {
198	    int		instance;
199	    CFStringRef	new_str;
200
201	    for (instance = 2, new_str = CFRetain(str);
202		 CFArrayContainsValue(cert_labels, r, new_str); instance++) {
203		CFRelease(new_str);
204		new_str
205		    = CFStringCreateWithFormat(NULL, NULL,
206					       CFSTR("%@ (%d)"), str,
207					       instance);
208	    }
209	    CFArrayAppendValue(cert_labels, new_str);
210	    r.length++;
211	    CFRelease(new_str);
212	    CFRelease(str);
213	    CFArrayAppendValue(certs_filtered, identity);
214	}
215    }
216    *ret_identities = certs_filtered;
217    return (cert_labels);
218}
219
220static CredentialsDialogueRef
221CredentialsDialogue_find(CFUserNotificationRef notif)
222{
223    CredentialsDialogueRef	scan;
224
225    LIST_FOREACH(scan, S_CredentialsDialogueHead_p, entries) {
226	if (scan->notif == notif)
227	    return (scan);
228    }
229    return (NULL);
230}
231
232static __inline__ CFOptionFlags
233S_CFUserNotificationResponse(CFOptionFlags flags)
234{
235    return (flags & 0x3);
236}
237
238static CFStringRef
239myCFUserNotificationCopyTextFieldValue(CFUserNotificationRef notif, int i)
240{
241    CFStringRef		str;
242
243    str = CFUserNotificationGetResponseValue(notif,
244					     kCFUserNotificationTextFieldValuesKey,
245					     i);
246    if (str == NULL || CFStringGetLength(str) == 0) {
247	return (NULL);
248    }
249    CFRetain(str);
250    return (str);
251}
252
253#define kPasswordChangeOldPasswordMissing	CFSTR("You must enter your old password")
254#define kPasswordChangeOldPasswordIncorrect	CFSTR("Your old password is incorrect")
255#define kPasswordChangeNewPasswordMissing	CFSTR("Enter and retype your new password")
256#define kPasswordChangeOldPasswordSameAsNew 	CFSTR("Your new password must be different than your old password")
257#define kPasswordChangeRetypeNewPassword	CFSTR("Retype your new password")
258#define kPasswordChangeNewPasswordsDoNotMatch	CFSTR("The new passwords do not match")
259
260
261static void
262CredentialsDialogue_response(CFUserNotificationRef notif,
263			     CFOptionFlags response_flags)
264{
265    int					count;
266    CredentialsDialogueRef		dialogue_p;
267    CFStringRef				failure_string = NULL;
268    CFStringRef				new_password_again = NULL;
269    CredentialsDialogueResponse		response;
270
271    dialogue_p = CredentialsDialogue_find(notif);
272    if (dialogue_p == NULL) {
273	/* should not happen */
274	return;
275    }
276    bzero(&response, sizeof(response));
277
278    switch (S_CFUserNotificationResponse(response_flags)) {
279    case kCFUserNotificationDefaultResponse:
280	if (dialogue_p->remember_information
281	    && response_flags & CFUserNotificationCheckBoxChecked(0)) {
282	    response.remember_information = TRUE;
283	}
284	count = 0;
285	if (dialogue_p->name_enabled) {
286	    response.username
287		= myCFUserNotificationCopyTextFieldValue(notif, count++);
288	}
289	if (dialogue_p->password_enabled) {
290	    response.password
291		= myCFUserNotificationCopyTextFieldValue(notif, count++);
292	}
293	if (dialogue_p->password_change) {
294	    response.new_password
295		= myCFUserNotificationCopyTextFieldValue(notif, count++);
296	    new_password_again
297		= myCFUserNotificationCopyTextFieldValue(notif, count++);
298	}
299	else if (dialogue_p->identity_list != NULL) {
300	    int		which_cert;
301
302	    which_cert = (response_flags
303			  & CFUserNotificationPopUpSelection(-1)) >> 24;
304	    if (which_cert > 0) {
305		response.chosen_identity = (SecIdentityRef)
306		    CFArrayGetValueAtIndex(dialogue_p->identity_list,
307					   which_cert - 1);
308		CFRetain(response.chosen_identity);
309	    }
310	    else if (dialogue_p->password_enabled == FALSE) {
311		/* user did not choose a certificate, clear the username too */
312		my_CFRelease(&response.username);
313	    }
314	}
315	break;
316    default:
317	response.user_cancelled = TRUE;
318	break;
319    }
320    if (dialogue_p->rls != NULL) {
321	CFRunLoopSourceInvalidate(dialogue_p->rls);
322	my_CFRelease(&dialogue_p->rls);
323    }
324    my_CFRelease(&dialogue_p->notif);
325
326    if (dialogue_p->password_change && response.user_cancelled == FALSE) {
327	/* verify that the old and new password information makes sense */
328	if (response.password == NULL) {
329	    /* no old password */
330	    failure_string = kPasswordChangeOldPasswordMissing;
331	}
332	else if (!CFEqual(response.password, dialogue_p->password)) {
333	    failure_string = kPasswordChangeOldPasswordIncorrect;
334	    my_CFRelease(&response.password);
335	}
336	if (response.new_password == NULL) {
337	    if (failure_string == NULL) {
338		failure_string = kPasswordChangeNewPasswordMissing;
339	    }
340	}
341	else if (response.password != NULL) {
342	    if (CFEqual(response.new_password, response.password)) {
343		failure_string = kPasswordChangeOldPasswordSameAsNew;
344		my_CFRelease(&response.new_password);
345		my_CFRelease(&new_password_again);
346	    }
347	    else if (new_password_again == NULL) {
348		if (failure_string == NULL) {
349		    failure_string = kPasswordChangeRetypeNewPassword;
350		}
351	    }
352	    else if (!CFEqual(response.new_password, new_password_again)) {
353		/* new and old passwords don't match */
354		if (failure_string == NULL) {
355		    failure_string = kPasswordChangeNewPasswordsDoNotMatch;
356		}
357		my_CFRelease(&new_password_again);
358	    }
359	}
360    }
361    if (failure_string != NULL) {
362	CFMutableDictionaryRef		overrides;
363
364	overrides = CFDictionaryCreateMutable(NULL, 0,
365					    &kCFTypeDictionaryKeyCallBacks,
366					    &kCFTypeDictionaryValueCallBacks);
367	CFDictionarySetValue(overrides, kOverrideMessage,
368			     failure_string);
369	if (response.password != NULL) {
370	    CFDictionarySetValue(overrides, kOverridePassword,
371				 response.password);
372	}
373	if (response.new_password != NULL) {
374	    CFDictionarySetValue(overrides, kOverrideNewPassword,
375				 response.new_password);
376	}
377	if (new_password_again != NULL) {
378	    CFDictionarySetValue(overrides, kOverrideNewPasswordAgain,
379				 new_password_again);
380	}
381	dialogue_p->notif
382	    = CredentialsDialogueCreateUserNotification(dialogue_p,
383							overrides);
384	dialogue_p->rls
385	    = CFUserNotificationCreateRunLoopSource(NULL, dialogue_p->notif,
386						    CredentialsDialogue_response,
387						    0);
388	CFRunLoopAddSource(CFRunLoopGetCurrent(), dialogue_p->rls,
389			   kCFRunLoopDefaultMode);
390	CFRelease(overrides);
391    }
392    else {
393	(*dialogue_p->func)(dialogue_p->arg1, dialogue_p->arg2, &response);
394    }
395    my_CFRelease(&response.username);
396    my_CFRelease(&response.password);
397    my_CFRelease(&response.new_password);
398    my_CFRelease(&new_password_again);
399    my_CFRelease(&response.chosen_identity);
400    return;
401}
402
403#define kNetworkPrefPanePath	"/System/Library/PreferencePanes/Network.prefPane"
404
405static CFURLRef
406copy_icon_url(CFStringRef icon)
407{
408    CFBundleRef		np_bundle;
409    CFURLRef		np_url;
410    CFURLRef		url = NULL;
411
412    np_url = CFURLCreateWithFileSystemPath(NULL,
413					   CFSTR(kNetworkPrefPanePath),
414					   kCFURLPOSIXPathStyle, FALSE);
415    if (np_url != NULL) {
416	np_bundle = CFBundleCreate(NULL, np_url);
417	if (np_bundle != NULL) {
418	    url = CFBundleCopyResourceURL(np_bundle, icon,
419					  CFSTR("icns"), NULL);
420	    if (url == NULL) {
421		url = CFBundleCopyResourceURL(np_bundle, icon,
422					      CFSTR("tiff"), NULL);
423	    }
424	    CFRelease(np_bundle);
425	}
426	CFRelease(np_url);
427    }
428    return (url);
429}
430
431static CFStringRef
432interface_type_for_ssid(CFStringRef ssid)
433{
434    return ((ssid != NULL) ? CFSTR("Airport") : CFSTR("Ethernet"));
435}
436
437static CFURLRef
438copy_icon_url_for_ssid(CFStringRef ssid)
439{
440    return (copy_icon_url(interface_type_for_ssid(ssid)));
441}
442
443
444#define kTitleAirPortCertificate	CFSTR("TitleAirPortCertificate")
445#define kTitleAirPortCertificateAndPassword CFSTR("TitleAirPortCertificateAndPassword")
446#define kTitleAirPortPassword		CFSTR("TitleAirPortPassword")
447
448#define kTitleEthernetCertificate	CFSTR("TitleEthernetCertificate")
449#define kTitleEthernetCertificateAndPassword  CFSTR("TitleEthernetCertificateAndPassword")
450#define kTitleEthernetPassword		CFSTR("TitleEthernetPassword")
451
452
453#define kTitleEthernetPasswordChange	CFSTR("Your password has expired for this network")
454#define kTitleAirPortPasswordChange	CFSTR("Your password has expired for network \"%@\"")
455
456
457static Boolean
458CredentialsDialogueInit(CredentialsDialogueRef dialogue_p,
459			CFDictionaryRef details)
460{
461    CFBundleRef			bundle;
462    CFStringRef 		name;
463    CFStringRef 		password;
464    CFStringRef			ssid;
465
466    bundle = get_bundle();
467    if (bundle == NULL) {
468	EAPLOG_FL(LOG_NOTICE, "Can't get bundle");
469	goto failed;
470    }
471    dialogue_p->password_change
472	= CFDictionaryContainsKey(details,
473				  kCredentialsDialoguePasswordChangeRequired);
474    password = CFDictionaryGetValue(details, kCredentialsDialoguePassword);
475    if (dialogue_p->password_change) {
476	if (password == NULL) {
477	    EAPLOG_FL(LOG_NOTICE, "old password required for password change");
478	    goto failed;
479	}
480	dialogue_p->password = CFRetain(password);
481	dialogue_p->password_enabled = TRUE;
482    }
483    else if (password == NULL
484	     || isA_CFType(password, CFNullGetTypeID()) == FALSE) {
485	dialogue_p->password_enabled = TRUE;
486    }
487    name = CFDictionaryGetValue(details, kCredentialsDialogueAccountName);
488    if (name == NULL
489	|| isA_CFType(name, CFNullGetTypeID()) == FALSE) {
490	dialogue_p->name_enabled = TRUE;
491	if (name != NULL) {
492	    dialogue_p->name = CFRetain(name);
493	}
494    }
495    if (CFDictionaryContainsKey(details,
496				kCredentialsDialogueRememberInformation)) {
497	dialogue_p->remember_information = TRUE;
498    }
499
500    if (dialogue_p->password_change == FALSE) {
501	CFArrayRef 		certs;
502
503	certs = CFDictionaryGetValue(details, kCredentialsDialogueCertificates);
504	if (certs != NULL) {
505	    CFStringRef		cert_label;
506
507	    cert_label = (dialogue_p->password_enabled)
508		? CFSTR("No certificate selected")
509		: CFSTR("Select a certificate");
510	    dialogue_p->identity_labels
511		= copy_certificate_labels(certs, cert_label,
512					  &dialogue_p->identity_list);
513	}
514    }
515    ssid = CFDictionaryGetValue(details, kCredentialsDialogueSSID);
516    if (ssid != NULL) {
517	dialogue_p->ssid = CFRetain(ssid);
518    }
519    dialogue_p->localization_url = CFBundleCopyBundleURL(bundle);
520    dialogue_p->icon_url = copy_icon_url_for_ssid(ssid);
521    return (TRUE);
522
523 failed:
524    return (FALSE);
525}
526
527static CFUserNotificationRef
528CredentialsDialogueCreateUserNotification(CredentialsDialogueRef dialogue_p,
529					  CFDictionaryRef overrides)
530{
531    CFMutableArrayRef 		array;
532    CFMutableDictionaryRef	dict;
533    SInt32			error = 0;
534    CFOptionFlags		flags = 0;
535    CFUserNotificationRef 	notif = NULL;
536    CFIndex			password_index = 0;
537    CFStringRef 		title;
538
539    dict = CFDictionaryCreateMutable(NULL, 0,
540				     &kCFTypeDictionaryKeyCallBacks,
541				     &kCFTypeDictionaryValueCallBacks);
542
543    /* resource URLs */
544    if (dialogue_p->localization_url != NULL) {
545	CFDictionarySetValue(dict, kCFUserNotificationLocalizationURLKey,
546			     dialogue_p->localization_url);
547    }
548    if (dialogue_p->icon_url != NULL) {
549	CFDictionarySetValue(dict, kCFUserNotificationIconURLKey,
550			     dialogue_p->icon_url);
551    }
552
553    /* button titles */
554    CFDictionaryAddValue(dict, kCFUserNotificationAlternateButtonTitleKey,
555			 CFSTR("Cancel"));
556    if (dialogue_p->password_change) {
557	CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey,
558			     CFSTR("Change Password"));
559    }
560    else {
561	CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey,
562			     CFSTR("OK"));
563    }
564
565    /* text field values */
566    array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
567    if (dialogue_p->name_enabled) {
568	if (dialogue_p->name != NULL) {
569	    CFArrayAppendValue(array, dialogue_p->name);
570	}
571	else {
572	    CFArrayAppendValue(array, CFSTR(""));
573	}
574	password_index++;
575    }
576    if (dialogue_p->password_enabled) {
577	int		count;
578	int		i;
579	CFStringRef	keys[] = {
580	    kOverridePassword,
581	    kOverrideNewPassword,
582	    kOverrideNewPasswordAgain
583	};
584	int		keys_count = sizeof(keys) / sizeof(keys[0]);
585
586	count = dialogue_p->password_change ? keys_count : 1;
587	for (i = 0; i < count; i++) {
588	    CFStringRef		val = NULL;
589
590	    flags |= CFUserNotificationSecureTextField(password_index + i);
591	    if (overrides != NULL) {
592		val = CFDictionaryGetValue(overrides, keys[i]);
593	    }
594	    if (val == NULL) {
595		val = CFSTR("");
596	    }
597	    CFArrayAppendValue(array, val);
598	}
599    }
600    if (CFArrayGetCount(array) != 0) {
601	CFDictionaryAddValue(dict, kCFUserNotificationTextFieldValuesKey,
602			     array);
603    }
604    my_CFRelease(&array);
605
606    /* remember information checkbox */
607    if (dialogue_p->remember_information) {
608	array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
609	CFArrayAppendValue(array, CFSTR("Remember information"));
610	CFDictionarySetValue(dict, kCFUserNotificationCheckBoxTitlesKey,
611			     array);
612	my_CFRelease(&array);
613	flags |= CFUserNotificationCheckBoxChecked(0);
614    }
615
616    /* certificate pop-up */
617    if (dialogue_p->identity_labels != NULL) {
618	CFDictionarySetValue(dict, kCFUserNotificationPopUpTitlesKey,
619			     dialogue_p->identity_labels);
620    }
621
622    /* text field labels */
623    if (dialogue_p->name_enabled || dialogue_p->password_enabled) {
624	array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
625	if (dialogue_p->name_enabled) {
626	    if (dialogue_p->password_enabled) {
627		CFArrayAppendValue(array, CFSTR("User Name:"));
628	    }
629	    else {
630		CFArrayAppendValue(array, CFSTR("Account Name (optional):"));
631	    }
632	}
633	if (dialogue_p->password_change) {
634	    CFArrayAppendValue(array, CFSTR("Old Password:"));
635	    CFArrayAppendValue(array, CFSTR("New Password:"));
636	    CFArrayAppendValue(array, CFSTR("Retype New Password:"));
637	}
638	else if (dialogue_p->password_enabled) {
639	    CFArrayAppendValue(array, CFSTR("Password:"));
640	}
641
642	CFDictionaryAddValue(dict, kCFUserNotificationTextFieldTitlesKey,
643			     array);
644	my_CFRelease(&array);
645    }
646
647    /* title */
648    if (dialogue_p->password_change) {
649	title = copy_localized_string(get_bundle(),
650				      kTitleEthernetPasswordChange,
651				      kTitleAirPortPasswordChange,
652				      dialogue_p->ssid);
653    }
654    else if (dialogue_p->identity_labels != NULL
655	     && dialogue_p->password_enabled) {
656	title = copy_localized_string(get_bundle(),
657				      kTitleEthernetCertificateAndPassword,
658				      kTitleAirPortCertificateAndPassword,
659				      dialogue_p->ssid);
660    }
661    else if (dialogue_p->identity_labels == NULL) {
662	title = copy_localized_string(get_bundle(),
663				      kTitleEthernetPassword,
664				      kTitleAirPortPassword,
665				      dialogue_p->ssid);
666    }
667    else {
668	title = copy_localized_string(get_bundle(),
669				      kTitleEthernetCertificate,
670				      kTitleAirPortCertificate,
671				      dialogue_p->ssid);
672    }
673    CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, title);
674    CFRelease(title);
675
676    /* message */
677    if (overrides != NULL) {
678	CFStringRef	message;
679
680	message = CFDictionaryGetValue(overrides, kOverrideMessage);
681	if (message != NULL) {
682	    CFDictionaryAddValue(dict, kCFUserNotificationAlertMessageKey,
683				 message);
684	}
685    }
686    notif = CFUserNotificationCreate(NULL, 0, flags, &error, dict);
687    if (notif == NULL) {
688	EAPLOG_FL(LOG_NOTICE, "CFUserNotificationCreate failed, %d", error);
689    }
690    my_CFRelease(&dict);
691    return (notif);
692}
693
694CredentialsDialogueRef
695CredentialsDialogue_create(CredentialsDialogueResponseCallBack func,
696			   const void * arg1, const void * arg2,
697			   CFDictionaryRef details)
698{
699    CredentialsDialogueRef	dialogue_p;
700    CFUserNotificationRef 	notif = NULL;
701    CFRunLoopSourceRef		rls = NULL;
702
703    dialogue_p = malloc(sizeof(*dialogue_p));
704    if (dialogue_p == NULL) {
705	EAPLOG_FL(LOG_NOTICE, "malloc failed");
706	return (NULL);
707    }
708    bzero(dialogue_p, sizeof(*dialogue_p));
709    if (CredentialsDialogueInit(dialogue_p, details) == FALSE) {
710	goto failed;
711    }
712    notif = CredentialsDialogueCreateUserNotification(dialogue_p, NULL);
713    if (notif == NULL) {
714	goto failed;
715    }
716    rls = CFUserNotificationCreateRunLoopSource(NULL, notif,
717						CredentialsDialogue_response,
718						0);
719    if (rls == NULL) {
720	EAPLOG_FL(LOG_NOTICE, "CFUserNotificationCreateRunLoopSource failed");
721	goto failed;
722    }
723    CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
724    dialogue_p->notif = notif;
725    dialogue_p->rls = rls;
726    dialogue_p->func = func;
727    dialogue_p->arg1 = arg1;
728    dialogue_p->arg2 = arg2;
729    LIST_INSERT_HEAD(S_CredentialsDialogueHead_p, dialogue_p, entries);
730    return (dialogue_p);
731
732 failed:
733    CredentialsDialogueFreeElements(dialogue_p);
734    free(dialogue_p);
735    my_CFRelease(&notif);
736    my_CFRelease(&rls);
737    return (NULL);
738}
739
740static void
741CredentialsDialogueFreeElements(CredentialsDialogueRef dialogue_p)
742{
743    my_CFRelease(&dialogue_p->icon_url);
744    my_CFRelease(&dialogue_p->identity_list);
745    my_CFRelease(&dialogue_p->identity_labels);
746    my_CFRelease(&dialogue_p->localization_url);
747    my_CFRelease(&dialogue_p->name);
748    if (dialogue_p->notif != NULL) {
749	(void)CFUserNotificationCancel(dialogue_p->notif);
750	my_CFRelease(&dialogue_p->notif);
751    }
752    my_CFRelease(&dialogue_p->password);
753    if (dialogue_p->rls != NULL) {
754	CFRunLoopSourceInvalidate(dialogue_p->rls);
755	my_CFRelease(&dialogue_p->rls);
756    }
757    my_CFRelease(&dialogue_p->ssid);
758    return;
759}
760
761void
762CredentialsDialogue_free(CredentialsDialogueRef * dialogue_p_p)
763{
764    CredentialsDialogueRef dialogue_p = *dialogue_p_p;
765
766    if (dialogue_p) {
767	LIST_REMOVE(dialogue_p, entries);
768	CredentialsDialogueFreeElements(dialogue_p);
769	free(dialogue_p);
770    }
771    *dialogue_p_p = NULL;
772    return;
773}
774
775/**
776 ** TrustDialogue
777 **/
778#include <signal.h>
779#include <CoreFoundation/CFData.h>
780#include <CoreFoundation/CFPropertyList.h>
781
782struct TrustDialogue_e;
783#define LIST_HEAD_TrustDialogueHead	LIST_HEAD(TrustDialogueHead, TrustDialogue_s)
784static LIST_HEAD_TrustDialogueHead 	S_trust_head;
785static struct TrustDialogueHead * S_TrustDialogueHead_p = &S_trust_head;
786
787#define LIST_ENTRY_TrustDialogue	LIST_ENTRY(TrustDialogue_s)
788
789struct TrustDialogue_s {
790    LIST_ENTRY_TrustDialogue		entries;
791
792    TrustDialogueResponseCallBack 	func;
793    const void *			arg1;
794    const void *			arg2;
795    pid_t				pid;
796    int					fdp[2];
797    CFDictionaryRef			trust_plist;
798};
799
800static TrustDialogueRef
801TrustDialogue_find(pid_t pid)
802{
803    TrustDialogueRef	scan;
804
805    LIST_FOREACH(scan, S_TrustDialogueHead_p, entries) {
806	if (scan->pid == pid)
807	    return (scan);
808    }
809    return (NULL);
810}
811
812
813static void
814TrustDialogue_callback(pid_t pid, int status, __unused struct rusage * rusage,
815		       __unused void * context)
816{
817    TrustDialogueRef		dialogue_p;
818    TrustDialogueResponse	response;
819
820    dialogue_p = TrustDialogue_find(pid);
821    if (dialogue_p == NULL) {
822	return;
823    }
824    response.proceed = FALSE;
825    if (WIFEXITED(status)) {
826	int	exit_code = WEXITSTATUS(status);
827
828	EAPLOG_FL(LOG_DEBUG, "child %d exit(%d)", pid, exit_code);
829	if (exit_code == 0) {
830	    response.proceed = 1;
831	}
832    }
833    else if (WIFSIGNALED(status)) {
834	EAPLOG_FL(LOG_DEBUG, "child %d signaled(%d)", pid, WTERMSIG(status));
835    }
836    dialogue_p->pid = -1;
837    (*dialogue_p->func)(dialogue_p->arg1, dialogue_p->arg2, &response);
838    return;
839}
840
841static void
842TrustDialogue_setup_child(TrustDialogueRef dialogue_p)
843{
844    int	fd;
845    int i;
846
847    /* close open FD's except for the read end of the pipe */
848    for (i = getdtablesize() - 1; i >= 0; i--) {
849	if (i != dialogue_p->fdp[0]) {
850	    close(i);
851	}
852    }
853    if (dialogue_p->fdp[0] != STDIN_FILENO) {
854	dup(dialogue_p->fdp[0]);	/* stdin */
855	close(dialogue_p->fdp[0]);
856    }
857    fd = open(_PATH_DEVNULL, O_RDWR, 0);/* stdout */
858    dup(fd);				/* stderr */
859    return;
860}
861
862static void
863TrustDialogue_setup_parent(TrustDialogueRef dialogue_p)
864{
865    size_t		count;
866    CFDataRef		data;
867    size_t		write_count;
868
869    close(dialogue_p->fdp[0]); 	/* close the read end */
870    dialogue_p->fdp[0] = -1;
871
872    data = CFPropertyListCreateXMLData(NULL,
873				       dialogue_p->trust_plist);
874    count = CFDataGetLength(data);
875    /* disable SIGPIPE if it's currently enabled? XXX */
876    write_count = write(dialogue_p->fdp[1],
877			(void *)CFDataGetBytePtr(data),
878			count);
879    /* enable SIGPIPE if it was enabled? XXX */
880    my_CFRelease(&data);
881
882    if (write_count != count) {
883	if (write_count == -1) {
884	    EAPLOG_FL(LOG_NOTICE, "write on pipe failed, %s",
885		      strerror(errno));
886	}
887	else {
888	    EAPLOG_FL(LOG_NOTICE, "wrote %d expected %d",
889		      write_count, count);
890	}
891    }
892    close(dialogue_p->fdp[1]);	/* close write end to deliver EOF to reader */
893    dialogue_p->fdp[1] = -1;
894    return;
895}
896
897static void
898TrustDialogue_setup(pid_t pid, void * context)
899{
900    TrustDialogueRef	Dialogue_p = (TrustDialogueRef)context;
901
902    if (pid == 0) {
903	TrustDialogue_setup_child(Dialogue_p);
904    }
905    else {
906	TrustDialogue_setup_parent(Dialogue_p);
907    }
908    return;
909}
910
911#define EAPTLSTRUST_PATH	"/System/Library/PrivateFrameworks/EAP8021X.framework/Support/eaptlstrust.app/Contents/MacOS/eaptlstrust"
912
913static pthread_once_t initialized = PTHREAD_ONCE_INIT;
914
915TrustDialogueRef
916TrustDialogue_create(TrustDialogueResponseCallBack func,
917		     const void * arg1, const void * arg2,
918		     CFDictionaryRef trust_info, CFTypeRef ssid)
919{
920    char * 			argv[2] = {EAPTLSTRUST_PATH, NULL};
921    CFBundleRef			bundle;
922    CFStringRef			caller_label;
923    CFMutableDictionaryRef 	dict;
924    TrustDialogueRef		dialogue_p;
925    extern void			_SCDPluginExecInit();
926
927    bundle = get_bundle();
928    if (bundle == NULL) {
929	EAPLOG_FL(LOG_NOTICE, "Can't get bundle");
930	return (NULL);
931    }
932    pthread_once(&initialized, _SCDPluginExecInit);
933    dialogue_p = (TrustDialogueRef)malloc(sizeof(*dialogue_p));
934    bzero(dialogue_p, sizeof(*dialogue_p));
935    dialogue_p->pid = -1;
936    dialogue_p->fdp[0] = dialogue_p->fdp[1] = -1;
937    if (pipe(dialogue_p->fdp) == -1) {
938	EAPLOG_FL(LOG_NOTICE, "pipe failed, %s",
939		  strerror(errno));
940	goto failed;
941    }
942    dict = CFDictionaryCreateMutable(NULL, 0,
943				     &kCFTypeDictionaryKeyCallBacks,
944				     &kCFTypeDictionaryValueCallBacks);
945    CFDictionarySetValue(dict, CFSTR("TrustInformation"), trust_info);
946    CFDictionarySetValue(dict, CFSTR("Icon"),
947			 interface_type_for_ssid(ssid));
948    caller_label = copy_localized_title(bundle, ssid);
949    if (caller_label != NULL) {
950	CFDictionarySetValue(dict, CFSTR("CallerLabel"),
951			     caller_label);
952	CFRelease(caller_label);
953    }
954    dialogue_p->trust_plist = CFDictionaryCreateCopy(NULL, dict);
955    my_CFRelease(&dict);
956    dialogue_p->pid
957	= _SCDPluginExecCommand2(TrustDialogue_callback, NULL,
958				 geteuid(), getegid(),
959				 EAPTLSTRUST_PATH, argv,
960				 TrustDialogue_setup,
961				 dialogue_p);
962    if (dialogue_p->pid == -1) {
963	EAPLOG_FL(LOG_NOTICE,
964		  "_SCDPluginExecCommand2 failed, %s",
965		  strerror(errno));
966	goto failed;
967    }
968    dialogue_p->func = func;
969    dialogue_p->arg1 = arg1;
970    dialogue_p->arg2 = arg2;
971    LIST_INSERT_HEAD(S_TrustDialogueHead_p, dialogue_p, entries);
972    return (dialogue_p);
973
974 failed:
975    TrustDialogue_free(&dialogue_p);
976    return (NULL);
977}
978
979CFDictionaryRef
980TrustDialogue_trust_info(TrustDialogueRef dialogue_p)
981{
982    if (dialogue_p->trust_plist == NULL) {
983	return (NULL);
984    }
985    return (CFDictionaryGetValue(dialogue_p->trust_plist,
986				 CFSTR("TrustInformation")));
987}
988
989void
990TrustDialogue_free(TrustDialogueRef * dialogue_p_p)
991{
992    TrustDialogueRef	dialogue_p;
993
994    if (dialogue_p_p == NULL) {
995	return;
996    }
997    dialogue_p = *dialogue_p_p;
998    if (dialogue_p != NULL) {
999	LIST_REMOVE(dialogue_p, entries);
1000	if (dialogue_p->pid != -1) {
1001	    if (kill(dialogue_p->pid, SIGHUP)) {
1002		EAPLOG_FL(LOG_NOTICE, "kill(%d) failed, %s", dialogue_p->pid,
1003			  strerror(errno));
1004	    }
1005	}
1006	if (dialogue_p->fdp[0] != -1) {
1007	    close(dialogue_p->fdp[0]);
1008	}
1009	if (dialogue_p->fdp[0] != -1) {
1010	    close(dialogue_p->fdp[1]);
1011	}
1012	my_CFRelease(&dialogue_p->trust_plist);
1013	free(dialogue_p);
1014	*dialogue_p_p = NULL;
1015    }
1016    return;
1017}
1018
1019/**
1020 ** AlertDialogue
1021 **/
1022
1023struct AlertDialogue_s;
1024#define LIST_HEAD_AlertDialogueHead LIST_HEAD(AlertDialogueHead, AlertDialogue_s)
1025static LIST_HEAD_AlertDialogueHead  	S_AlertDialogueHead;
1026static struct AlertDialogueHead * S_AlertDialogueHead_p = &S_AlertDialogueHead;
1027
1028#define LIST_ENTRY_AlertDialogue	LIST_ENTRY(AlertDialogue_s)
1029
1030struct AlertDialogue_s {
1031    LIST_ENTRY_AlertDialogue		entries;
1032    CFUserNotificationRef 		notif;
1033    CFRunLoopSourceRef			rls;
1034    AlertDialogueResponseCallBack 	func;
1035    const void *			arg1;
1036    const void *			arg2;
1037};
1038
1039#define kAuthenticationFailedEthernet	CFSTR("AUTHENTICATION_FAILED")
1040#define kAuthenticationFailedAirPort  	CFSTR("AUTHENTICATION_FAILED_AIRPORT")
1041
1042static CFUserNotificationRef
1043AlertDialogueCopy(AlertDialogueRef dialogue_p,
1044		  CFBundleRef bundle, CFStringRef message, CFStringRef ssid)
1045{
1046    CFMutableDictionaryRef	dict = NULL;
1047    SInt32			error = 0;
1048    CFUserNotificationRef 	notif = NULL;
1049    CFStringRef			title;
1050    CFURLRef			url;
1051
1052    dict = CFDictionaryCreateMutable(NULL, 0,
1053				     &kCFTypeDictionaryKeyCallBacks,
1054				     &kCFTypeDictionaryValueCallBacks);
1055    url = CFBundleCopyBundleURL(bundle);
1056    if (url != NULL) {
1057	CFDictionarySetValue(dict, kCFUserNotificationLocalizationURLKey,
1058			     url);
1059	CFRelease(url);
1060    }
1061    url = copy_icon_url_for_ssid(ssid);
1062    if (url != NULL) {
1063	CFDictionarySetValue(dict, kCFUserNotificationIconURLKey,
1064			     url);
1065	CFRelease(url);
1066    }
1067    CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey,
1068			 CFSTR("DISCONNECT"));
1069
1070    title = copy_localized_string(bundle,
1071				  kAuthenticationFailedEthernet,
1072				  kAuthenticationFailedAirPort,
1073				  ssid);
1074    CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, title);
1075    CFRelease(title);
1076    CFDictionaryAddValue(dict, kCFUserNotificationAlertMessageKey, message);
1077    notif = CFUserNotificationCreate(NULL, 0, 0, &error, dict);
1078    if (notif == NULL) {
1079	EAPLOG_FL(LOG_NOTICE, "CFUserNotificationCreate failed, %d", error);
1080    }
1081    my_CFRelease(&dict);
1082    return (notif);
1083}
1084
1085static AlertDialogueRef
1086AlertDialogue_find(CFUserNotificationRef notif)
1087{
1088    AlertDialogueRef	scan;
1089
1090    LIST_FOREACH(scan, S_AlertDialogueHead_p, entries) {
1091	if (scan->notif == notif)
1092	    return (scan);
1093    }
1094    return (NULL);
1095}
1096
1097static void
1098AlertDialogue_response(CFUserNotificationRef notif,
1099		       CFOptionFlags response_flags)
1100{
1101    volatile AlertDialogueRef		dialogue_p;
1102
1103    dialogue_p = AlertDialogue_find(notif);
1104    if (dialogue_p == NULL) {
1105	/* should not happen */
1106	return;
1107    }
1108    if (dialogue_p->rls != NULL) {
1109	CFRunLoopSourceInvalidate(dialogue_p->rls);
1110	my_CFRelease(&dialogue_p->rls);
1111    }
1112    my_CFRelease(&dialogue_p->notif);
1113    (*dialogue_p->func)(dialogue_p->arg1, dialogue_p->arg2);
1114    return;
1115}
1116
1117AlertDialogueRef
1118AlertDialogue_create(AlertDialogueResponseCallBack func,
1119		     const void * arg1, const void * arg2,
1120		     CFStringRef message, CFStringRef ssid)
1121{
1122    CFBundleRef			bundle;
1123    AlertDialogueRef		dialogue_p;
1124    CFUserNotificationRef 	notif = NULL;
1125    CFRunLoopSourceRef		rls = NULL;
1126
1127    bundle = get_bundle();
1128    if (bundle == NULL) {
1129	EAPLOG_FL(LOG_NOTICE, "Can't get bundle");
1130	return (NULL);
1131    }
1132    dialogue_p = malloc(sizeof(*dialogue_p));
1133    if (dialogue_p == NULL) {
1134	EAPLOG_FL(LOG_NOTICE, "malloc failed");
1135	return (NULL);
1136    }
1137    bzero(dialogue_p, sizeof(*dialogue_p));
1138    notif = AlertDialogueCopy(dialogue_p, bundle, message, ssid);
1139    if (notif == NULL) {
1140	goto failed;
1141    }
1142    rls = CFUserNotificationCreateRunLoopSource(NULL, notif,
1143						AlertDialogue_response,
1144						0);
1145    if (rls == NULL) {
1146	EAPLOG_FL(LOG_NOTICE, "CFUserNotificationCreateRunLoopSource failed");
1147	goto failed;
1148    }
1149    CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1150    dialogue_p->notif = notif;
1151    dialogue_p->rls = rls;
1152    dialogue_p->func = func;
1153    dialogue_p->arg1 = arg1;
1154    dialogue_p->arg2 = arg2;
1155    LIST_INSERT_HEAD(S_AlertDialogueHead_p, dialogue_p, entries);
1156    return (dialogue_p);
1157
1158 failed:
1159    free(dialogue_p);
1160    my_CFRelease(&notif);
1161    my_CFRelease(&rls);
1162    return (NULL);
1163}
1164
1165
1166void
1167AlertDialogue_free(AlertDialogueRef * dialogue_p_p)
1168{
1169    AlertDialogueRef dialogue_p = *dialogue_p_p;
1170
1171    if (dialogue_p) {
1172	LIST_REMOVE(dialogue_p, entries);
1173	if (dialogue_p->rls) {
1174	    CFRunLoopSourceInvalidate(dialogue_p->rls);
1175	    my_CFRelease(&dialogue_p->rls);
1176	}
1177	if (dialogue_p->notif) {
1178	    (void)CFUserNotificationCancel(dialogue_p->notif);
1179	    my_CFRelease(&dialogue_p->notif);
1180	}
1181	bzero(dialogue_p, sizeof(*dialogue_p));
1182	free(dialogue_p);
1183    }
1184    *dialogue_p_p = NULL;
1185    return;
1186}
1187
1188#ifdef TEST_DIALOGUE
1189#include <SystemConfiguration/SCPrivate.h>
1190
1191void
1192my_callback(const void * arg1, const void * arg2, CredentialsDialogueResponseRef response)
1193{
1194    CredentialsDialogueRef *	dialogue_p_p = (CredentialsDialogueRef *)arg1;
1195    CredentialsDialogueRef	temp = *dialogue_p_p;
1196
1197    if (response->username) {
1198	SCPrint(TRUE, stdout, CFSTR("Account: %@\n"), response->username);
1199    }
1200    if (response->password) {
1201	SCPrint(TRUE, stdout, CFSTR("Password: %@\n"), response->password);
1202    }
1203    if (response->new_password) {
1204	SCPrint(TRUE, stdout, CFSTR("New Password: %@\n"),
1205		response->new_password);
1206    }
1207    if (response->chosen_identity != NULL) {
1208	SecCertificateRef	cert;
1209	CFStringRef		str = NULL;
1210
1211	SecIdentityCopyCertificate(response->chosen_identity, &cert);
1212	if (cert != NULL) {
1213	    str = SecCertificateCopyShortDescription(NULL, cert, NULL);
1214	    CFRelease(cert);
1215	}
1216	SCPrint(TRUE, stdout, CFSTR("Identity: %@\n"), str);
1217	CFRelease(str);
1218    }
1219    if (response->remember_information) {
1220	printf("Remember information checked\n");
1221    }
1222    if (response->user_cancelled) {
1223	printf("User cancelled\n");
1224    }
1225    CredentialsDialogue_free(&temp);
1226    return;
1227}
1228
1229void
1230my_alert_callback(const void * arg1, const void * arg2)
1231{
1232    AlertDialogueRef	alert_p;
1233    AlertDialogueRef *	alert_p_p = (AlertDialogueRef *)arg1;
1234
1235    if (alert_p_p == NULL) {
1236	printf("NULL pointer!\n");
1237	return;
1238    }
1239    alert_p = *alert_p_p;
1240    AlertDialogue_free(alert_p_p);
1241    printf("Alert done\n");
1242    return;
1243}
1244
1245int
1246main(int argc, char * argv[])
1247{
1248    AlertDialogueRef	   	alert_p;
1249    AlertDialogueRef *	  	alert_p_p = &alert_p;
1250    CredentialsDialogueRef dialogue_p;
1251    CredentialsDialogueRef dialogue_p2;
1252    CredentialsDialogueRef dialogue_p3;
1253    CFMutableDictionaryRef	dict = NULL;
1254    CredentialsDialogueRef * p = &dialogue_p;
1255    CredentialsDialogueRef * p2 = &dialogue_p2;
1256    CredentialsDialogueRef * p3 = &dialogue_p3;
1257    CFArrayRef		   certs = NULL;
1258
1259    (void)EAPSecIdentityListCreate(&certs);
1260
1261    /* dialogue 1 */
1262    dict = CFDictionaryCreateMutable(NULL, 0,
1263				     &kCFTypeDictionaryKeyCallBacks,
1264				     &kCFTypeDictionaryValueCallBacks);
1265    CFDictionarySetValue(dict, kCredentialsDialogueAccountName,
1266			 CFSTR("dieter"));
1267    /* disable the Password field */
1268    CFDictionarySetValue(dict, kCredentialsDialoguePassword,
1269			 kCFNull);
1270    CFDictionarySetValue(dict, kCredentialsDialogueSSID, CFSTR("SSID"));
1271    CFDictionarySetValue(dict, kCredentialsDialogueRememberInformation,
1272			 kCFBooleanTrue);
1273    if (certs != NULL) {
1274	CFDictionarySetValue(dict, kCredentialsDialogueCertificates, certs);
1275    }
1276
1277    dialogue_p = CredentialsDialogue_create(my_callback, p, NULL, dict);
1278    CFRelease(dict);
1279
1280    /* dialogue 2 */
1281    dict = CFDictionaryCreateMutable(NULL, 0,
1282				     &kCFTypeDictionaryKeyCallBacks,
1283				     &kCFTypeDictionaryValueCallBacks);
1284    CFDictionarySetValue(dict, kCredentialsDialogueAccountName,
1285			 CFSTR("dieter"));
1286    CFDictionarySetValue(dict, kCredentialsDialogueRememberInformation,
1287			 kCFBooleanTrue);
1288    if (certs != NULL) {
1289	CFDictionarySetValue(dict, kCredentialsDialogueCertificates, certs);
1290    }
1291    dialogue_p2 = CredentialsDialogue_create(my_callback, p2, NULL, dict);
1292    CFRelease(dict);
1293
1294    /* dialogue 3 */
1295    dict = CFDictionaryCreateMutable(NULL, 0,
1296				     &kCFTypeDictionaryKeyCallBacks,
1297				     &kCFTypeDictionaryValueCallBacks);
1298    CFDictionarySetValue(dict, kCredentialsDialogueAccountName,
1299			 CFSTR("dieter"));
1300    CFDictionarySetValue(dict, kCredentialsDialoguePassword,
1301			 CFSTR("siegmund"));
1302    CFDictionarySetValue(dict, kCredentialsDialogueSSID, CFSTR("SomeSSID"));
1303    CFDictionarySetValue(dict, kCredentialsDialogueRememberInformation,
1304			 kCFBooleanTrue);
1305    CFDictionarySetValue(dict, kCredentialsDialoguePasswordChangeRequired,
1306			 kCFBooleanTrue);
1307    dialogue_p3 = CredentialsDialogue_create(my_callback, p3, NULL,
1308					     dict);
1309    if (dialogue_p3 == NULL) {
1310	fprintf(stderr, "failed to create password change dialogue\n");
1311    }
1312    alert_p = AlertDialogue_create(my_alert_callback, alert_p_p, NULL,
1313				   CFSTR("Here we are"), NULL);
1314    CFRunLoopRun();
1315    exit(0);
1316    return (0);
1317}
1318
1319#endif /* TEST_DIALOGUE */
1320