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 52static CFBundleRef bundle = 0; /* our bundle ref */ 53static char eapsim_unique[17]; 54 55static EAPClientModuleRef eapRef = NULL; 56static EAPClientPluginData eapData; 57static CFMutableDictionaryRef eapProperties = NULL; 58static CFDictionaryRef eapOptions = NULL; 59static struct EAP_Packet *eapSavePacket = NULL; 60 61extern EAPClientPluginFuncRef eapsim_introspect(EAPClientPluginFuncName name); 62 63/* ------------------------------------------------------------------------------------ 64 get the EAP dictionary from the options 65 ------------------------------------------------------------------------------------ */ 66static void 67EAPSIMGetOptions (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 ------------------------------------------------------------------------------------ */ 79static int 80EAPSIMLoad (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 ------------------------------------------------------------------------------------ */ 104int 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 ------------------------------------------------------------------------------------ */ 135int 136EAPSIMInit (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 192failed: 193 194 return ret; 195} 196 197/* ------------------------------------------------------------------------------------ 198 ------------------------------------------------------------------------------------ */ 199int 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 ------------------------------------------------------------------------------------ */ 230int 231EAPSIMProcess (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 ------------------------------------------------------------------------------------ */ 299int 300EAPSIMFree (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 ------------------------------------------------------------------------------------ */ 309int 310EAPSIMGetAttribute (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} 337