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