]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/eap_sim.c
ipsec-258.1.3.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / eap_sim.c
1 /*
2 * Copyright (c) 2012 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 <stdio.h>
25 #include <sys/types.h>
26 #include <sys/uio.h>
27 #include <unistd.h>
28 #include <syslog.h>
29 #include <sys/fcntl.h>
30 #include <CoreFoundation/CoreFoundation.h>
31 #include <CoreFoundation/CFBundle.h>
32 #include <mach/mach.h>
33 #include <EAP8021X/EAP.h>
34 #include <EAP8021X/EAPClientModule.h>
35 #include <EAP8021X/EAPClientProperties.h>
36 #if !TARGET_OS_EMBEDDED // This file is not built for Embedded
37 #include <Security/SecKeychain.h>
38 #include <Security/SecKeychainSearch.h>
39 #include <Security/SecKeychainItem.h>
40 #include <Security/SecIdentity.h>
41 #endif /* TARGET_OS_EMBEDDED */
42 #include <SystemConfiguration/SCNetworkConnection.h>
43 #include "plog.h"
44 #include "eap.h"
45 #include "eap_sim.h"
46
47 /*---------------------------------------------------------------------------
48 ** Internal routines
49 **---------------------------------------------------------------------------
50 */
51
52 static CFBundleRef bundle = 0; /* our bundle ref */
53 static char eapsim_unique[17];
54
55 static EAPClientModuleRef eapRef = NULL;
56 static EAPClientPluginData eapData;
57 static CFMutableDictionaryRef eapProperties = NULL;
58 static CFDictionaryRef eapOptions = NULL;
59 static struct EAP_Packet *eapSavePacket = NULL;
60
61 extern EAPClientPluginFuncRef eapsim_introspect(EAPClientPluginFuncName name);
62
63 /* ------------------------------------------------------------------------------------
64 get the EAP dictionary from the options
65 ------------------------------------------------------------------------------------ */
66 static void
67 EAPSIMGetOptions (void)
68 {
69 if (eapOptions)
70 return;
71
72 // no option, use empty dictionary
73 if (!eapOptions)
74 eapOptions = CFDictionaryCreate(0, 0, 0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
75 }
76
77 /* ------------------------------------------------------------------------------------
78 ------------------------------------------------------------------------------------ */
79 static int
80 EAPSIMLoad (void)
81 {
82 EAPClientModuleStatus status;
83
84 if (eapRef)
85 return EAP_NO_ERROR;
86
87 status = EAPClientModuleAddBuiltinModule(eapsim_introspect);
88 if (status != kEAPClientModuleStatusOK) {
89 plog(ASL_LEVEL_INFO, "EAP-SIM: EAPClientAddBuiltinModule(eapsim) failed %d\n", status);
90 return EAP_ERROR_GENERIC;
91 }
92
93 eapRef = EAPClientModuleLookup(kEAPTypeEAPSIM);
94 if (eapRef == NULL) {
95 plog(ASL_LEVEL_INFO, "EAP-SIM: EAPClientModuleLookup(eapsim) failed\n");
96 return EAP_ERROR_GENERIC;
97 }
98
99 return EAP_NO_ERROR;
100 }
101
102 /* ------------------------------------------------------------------------------------
103 ------------------------------------------------------------------------------------ */
104 int EAPSIMIdentity (char *identity, int maxlen)
105 {
106 CFStringRef identRef = NULL;
107 int error;
108 int ret = EAP_ERROR_GENERIC;
109
110 error = EAPSIMLoad();
111 if (error)
112 return error;
113
114 EAPSIMGetOptions();
115 if (eapOptions == NULL)
116 return ret;
117
118 identRef = EAPClientModulePluginUserName(eapRef, eapOptions);
119 if (identRef) {
120 if (CFStringGetCString(identRef, identity, maxlen, kCFStringEncodingUTF8))
121 ret = EAP_NO_ERROR;
122 CFRelease(identRef);
123 }
124
125 return ret;
126 }
127
128 /* ------------------------------------------------------------------------------------
129 Init routine called by the EAP engine when it needs the module.
130 Identity of the peer is known at this point.
131 mode is 0 for client, 1 for server.
132 cookie is the EAP engine context, to pass to subsequent calls to EAP.
133 context is EAP module context, that will be passed to subsequent calls to the module
134 ------------------------------------------------------------------------------------ */
135 int
136 EAPSIMInit (EAP_Input_t *eap_in, void **context, CFDictionaryRef eapOptions)
137 {
138 int error;
139 EAPClientModuleStatus status;
140 int ret = EAP_ERROR_GENERIC;
141
142 error = EAPSIMLoad();
143 if (error)
144 return error;
145
146 bundle = (CFBundleRef)eap_in->data;
147 if (bundle)
148 CFRetain(bundle);
149
150 EAPSIMGetOptions();
151
152 bzero(&eapData, sizeof(eapData));
153
154 /* remaining fields are read-only: */
155 *((bool *)&eapData.log_enabled) = 1;
156 *((uint32_t *)&eapData.log_level) = LOG_NOTICE;
157 *((uint32_t *)&eapData.mtu) = eap_in->mtu;
158 *((uint32_t *)&eapData.generation) = 0;/* changed when user updates */
159
160 arc4random_buf(eapsim_unique, sizeof(eapsim_unique) - 1);
161 eapsim_unique[sizeof(eapsim_unique)-1] = 0;
162
163 eapData.unique_id = eapsim_unique; /* used for TLS session resumption??? */
164 *((uint32_t *)&eapData.unique_id_length) = strlen(eapData.unique_id);
165
166 if (eapOptions) {
167 CFTypeRef value = CFDictionaryGetValue(eapOptions, kEAPPropertiesTypeEAPSIM);
168 if (value && CFGetTypeID(value) == CFDictionaryGetTypeID()) {
169 eapProperties = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, (CFDictionaryRef)value);
170 } else {
171 eapProperties = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, eapOptions);
172 }
173 } else
174 eapProperties = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
175 if (eapProperties == NULL) {
176 plog(ASL_LEVEL_ERR, "EAP-SIM: Cannot allocate memory\n");
177 goto failed;
178 }
179
180 *((CFDictionaryRef *)&eapData.properties) = (CFDictionaryRef)eapProperties;
181
182 status = EAPClientModulePluginInit(eapRef, &eapData, NULL, &error);
183 if (status != kEAPClientStatusOK) {
184 plog(ASL_LEVEL_ERR, "EAP-SIM: EAPClientPluginInit(eapsim) failed, error %d\n", status);
185 goto failed;
186 }
187
188 eapSavePacket = NULL;
189
190 return EAP_NO_ERROR;
191
192 failed:
193
194 return ret;
195 }
196
197 /* ------------------------------------------------------------------------------------
198 ------------------------------------------------------------------------------------ */
199 int EAPSIMDispose (void *context)
200 {
201
202 EAPClientModulePluginFree(eapRef, &eapData);
203 eapRef = 0;
204
205 if (bundle) {
206 CFRelease(bundle);
207 bundle = 0;
208 }
209
210 if (eapOptions) {
211 CFRelease(eapOptions);
212 eapOptions = 0;
213 }
214
215 if (eapProperties) {
216 CFRelease(eapProperties);
217 eapProperties = 0;
218 }
219
220 if (eapSavePacket) {
221 free(eapSavePacket);
222 eapSavePacket = 0;
223 }
224
225 return EAP_NO_ERROR;
226 }
227
228 /* ------------------------------------------------------------------------------------
229 ------------------------------------------------------------------------------------ */
230 int
231 EAPSIMProcess (void *context, EAP_Input_t *eap_in, EAP_Output_t *eap_out)
232 {
233 struct EAP_Packet *pkt_in = NULL;
234 struct EAP_Packet *pkt_out = NULL;
235 EAPClientStatus status;
236 EAPClientState state;
237 EAPClientDomainSpecificError error;
238 int do_process = 0;
239
240 // by default, ignore the message
241 eap_out->action = EAP_ACTION_NONE;
242 eap_out->data = 0;
243 eap_out->data_len = 0;
244
245 switch (eap_in->notification) {
246
247 case EAP_NOTIFICATION_DATA_FROM_UI:
248 plog(ASL_LEVEL_ERR, "unexpected EAP UI event");
249 break;
250
251 case EAP_NOTIFICATION_PACKET:
252
253 pkt_in = (struct EAP_Packet *)eap_in->data;
254 do_process = 1;
255 break;
256 }
257
258 if (do_process) {
259
260 state = EAPClientModulePluginProcess(eapRef, &eapData, (EAPPacketRef)pkt_in, (EAPPacketRef*)&pkt_out, &status, &error);
261 switch(state) {
262 case kEAPClientStateAuthenticating:
263 switch (status) {
264
265 case kEAPClientStatusOK:
266 eap_out->data = pkt_out;
267 eap_out->data_len = ntohs(pkt_out->len);
268 eap_out->action = EAP_ACTION_SEND;
269 break;
270
271 case kEAPClientStatusUserInputRequired:
272 plog(ASL_LEVEL_ERR, "unsupported EAP UI input");
273 default:
274 eap_out->action = EAP_ACTION_ACCESS_DENIED;
275 }
276 break;
277
278 case kEAPClientStateSuccess:
279 eap_out->action = EAP_ACTION_ACCESS_GRANTED;
280 break;
281
282 default:
283 case kEAPClientStateFailure:
284 eap_out->action = EAP_ACTION_ACCESS_DENIED;
285 break;
286 }
287 }
288
289 if (eapSavePacket) {
290 free(eapSavePacket);
291 eapSavePacket = 0;
292 }
293
294 return 0;
295 }
296
297 /* ------------------------------------------------------------------------------------
298 ------------------------------------------------------------------------------------ */
299 int
300 EAPSIMFree (void *context, EAP_Output_t *eap_out)
301 {
302
303 EAPClientModulePluginFreePacket(eapRef, &eapData, eap_out->data);
304 return EAP_NO_ERROR;
305 }
306
307 /* ------------------------------------------------------------------------------------
308 ------------------------------------------------------------------------------------ */
309 int
310 EAPSIMGetAttribute (void *context, EAP_Attribute_t *eap_attr)
311 {
312 void *data = NULL;
313 int len = 0;
314
315 eap_attr->data = 0;
316
317 switch (eap_attr->type) {
318
319 case EAP_ATTRIBUTE_MPPE_SEND_KEY:
320 data = EAPClientModulePluginSessionKey(eapRef, &eapData, &len);
321 break;
322 case EAP_ATTRIBUTE_MPPE_RECV_KEY:
323 data = EAPClientModulePluginServerKey(eapRef, &eapData, &len);
324 break;
325 }
326
327 if (data == NULL)
328 return -1;
329
330 eap_attr->data = data;
331 if (len == 32)
332 eap_attr->data_len = 64;
333 else
334 eap_attr->data_len = len;
335 return 0;
336 }