1/*
2 * Copyright (c) 2000 Apple Computer, 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#include <sys/types.h>
25#include <sys/uio.h>
26#include <unistd.h>
27#include <syslog.h>
28#include <sys/fcntl.h>
29#include <sys/wait.h>
30#include <signal.h>
31#include <paths.h>
32#include <CoreFoundation/CoreFoundation.h>
33#include <CoreFoundation/CFBundle.h>
34#include <mach/mach.h>
35#include <ppp/ppp_defs.h>
36#include <SystemConfiguration/SCNetworkConnection.h>
37
38#include "eaptls_ui.h"
39
40
41/* ------------------------------------------------------------------------------------
42 definitions
43------------------------------------------------------------------------------------ */
44
45/* ------------------------------------------------------------------------------------
46 internal functions
47------------------------------------------------------------------------------------ */
48extern uid_t uid;			/* Our real user-id */
49
50
51/* ------------------------------------------------------------------------------------
52 internal variables
53------------------------------------------------------------------------------------ */
54
55static CFBundleRef	bundleRef = 0;
56static int			pid = -1;
57static void			(*log_debug) __P((char *, ...)) = 0;
58static void			(*log_error) __P((char *, ...)) = 0;
59
60/* ------------------------------------------------------------------------------------
61------------------------------------------------------------------------------------ */
62int eaptls_ui_load(CFBundleRef bundle, void *logdebug, void *logerror)
63{
64    if (bundle == 0)
65        return -1;
66
67    bundleRef = bundle;
68	CFRetain(bundle);
69
70	log_debug = logdebug;
71	log_error = logerror;
72
73	pid = -1;
74    return 0;
75}
76
77/* ------------------------------------------------------------------------------------
78------------------------------------------------------------------------------------ */
79void eaptls_ui_dispose()
80{
81
82	if (pid != -1) {
83		kill(pid, SIGHUP);
84		pid = -1;
85	}
86
87	CFRelease(bundleRef);
88	bundleRef = NULL;
89}
90
91#define EAPTLSTRUST_PATH	"/System/Library/PrivateFrameworks/EAP8021X.framework/Support/eaptlstrust.app/Contents/MacOS/eaptlstrust"
92
93/* ------------------------------------------------------------------------------------
94------------------------------------------------------------------------------------ */
95static void
96eaptls_ui_setup_child(int fdp[2])
97{
98    int	fd, i;
99
100    /* close open FD's except for the read end of the pipe */
101    for (i = getdtablesize() - 1; i >= 0; i--) {
102		if (i != fdp[0])
103			close(i);
104    }
105    if (fdp[0] != STDIN_FILENO) {
106		dup(fdp[0]);	/* stdin */
107		close(fdp[0]);
108    }
109    fd = open(_PATH_DEVNULL, O_RDWR, 0);/* stdout */
110    dup(fd);				/* stderr */
111}
112
113/* ------------------------------------------------------------------------------------
114------------------------------------------------------------------------------------ */
115static void
116eaptls_ui_setup_parent(int fdp[2], CFDictionaryRef trust_info, CFStringRef caller_label)
117{
118    size_t					count, write_count;
119    CFMutableDictionaryRef 	dict;
120    CFDataRef				data;
121
122    close(fdp[0]); 	/* close the read end */
123    fdp[0] = -1;
124
125	dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
126	CFDictionarySetValue(dict, CFSTR("TrustInformation"), trust_info);
127	if (caller_label)
128		CFDictionarySetValue(dict, CFSTR("CallerLabel"), caller_label);
129
130    data = CFPropertyListCreateXMLData(NULL, dict);
131    count = CFDataGetLength(data);
132    /* disable SIGPIPE if it's currently enabled? XXX */
133    write_count = write(fdp[1], (void *)CFDataGetBytePtr(data), count);
134
135    /* enable SIGPIPE if it was enabled? XXX */
136    CFRelease(data);
137	CFRelease(dict);
138
139    if (write_count != count) {
140		if (write_count == -1) {
141			if (log_error)
142				(log_error)("EAP-TLS: dialog setup parent failed to write on pipe, %m\n");
143		}
144		else {
145			if (log_error)
146				(log_error)("EAP-TLS: dialog setup parent failed to write on pipe (wrote %d, expected %d)\n",
147								write_count, count);
148		}
149    }
150    close(fdp[1]);	/* close write end to deliver EOF to reader */
151    fdp[1] = -1;
152}
153
154
155/* ------------------------------------------------------------------------------------
156------------------------------------------------------------------------------------ */
157static int
158eaptls_ui_dialog(CFDictionaryRef trust_info, CFStringRef caller_label)
159{
160	int fdp[2], err, status, ret = RESPONSE_ERROR;
161
162    fdp[0] = fdp[1] = -1;
163    if (pipe(fdp) == -1) {
164		if (log_error)
165			(log_error)("EAP-TLS: dialog failed to create pipe, %m\n");
166		goto fail;
167    }
168
169	pid = fork();
170	if (pid < 0)
171		goto fail;
172
173	if (pid == 0) {
174		// child
175
176		setuid(uid);
177		eaptls_ui_setup_child(fdp);
178        err = execle(EAPTLSTRUST_PATH, EAPTLSTRUST_PATH, (char *)0, (char *)0);
179        exit(errno);
180	}
181
182	// parent
183
184	eaptls_ui_setup_parent(fdp, trust_info, caller_label);
185
186    while (waitpid(pid, &status, 0) < 0) {
187        if (errno == EINTR)
188            continue;
189		if (log_error)
190			(log_error)("EAP-TLS: in parent, child error (%m)\n");
191      goto fail;
192    }
193
194	if (WIFEXITED(status)) {
195		switch (WEXITSTATUS(status)) {
196			case 0:
197				// OK, no error
198				ret = RESPONSE_OK;
199				break;
200			case 1:
201				// user cancelled
202				ret = RESPONSE_CANCEL;
203				break;
204			default:
205				// error or certificate failure
206				ret = RESPONSE_ERROR;
207		}
208	}
209
210	return ret;
211
212 fail:
213	if (fdp[0] != -1)
214		close(fdp[0]);
215	if (fdp[1] != -1)
216		close(fdp[1]);
217    return RESPONSE_ERROR;
218}
219
220/* ------------------------------------------------------------------------------------
221Perform EAP TLS trust evaluation
222------------------------------------------------------------------------------------ */
223int eaptls_ui_trusteval(CFDictionaryRef publishedProperties, void *data_in, int data_in_len,
224                    void **data_out, int *data_out_len)
225{
226    eaptls_ui_ctx *ctx = (eaptls_ui_ctx *)data_in;
227	CFStringRef	copy = NULL;
228
229	copy = CFBundleCopyLocalizedString(bundleRef, CFSTR("VPN Authentication"), CFSTR("VPN Authentication"), NULL);
230	ctx->response = eaptls_ui_dialog(publishedProperties, copy ? copy : CFSTR("VPN Authentication"));
231	if (copy)
232		CFRelease(copy);
233
234    *data_out = data_in;
235    *data_out_len = data_in_len;
236    return 0;
237}
238
239