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 * main.c 26 */ 27 28/* 29 * Modification History 30 * 31 * October 26, 2001 Dieter Siegmund (dieter@apple) 32 * - created 33 */ 34 35#include <stdlib.h> 36#include <unistd.h> 37#include <string.h> 38#include <fcntl.h> 39#include <stdio.h> 40#include <sys/types.h> 41#include <sys/stat.h> 42#include <sys/errno.h> 43#include <net/if_types.h> 44#include <sysexits.h> 45#include <sys/types.h> 46#include <paths.h> 47#include <pwd.h> 48#include <grp.h> 49#include <sys/time.h> 50 51#include <CoreFoundation/CFRunLoop.h> 52 53#include <EAP8021X/LinkAddresses.h> 54#include <EAP8021X/EAPClientModule.h> 55#include <SystemConfiguration/SCPreferences.h> 56#include <SystemConfiguration/SCValidation.h> 57#include <SystemConfiguration/SCPrivate.h> 58#include "EAPOLSocketPrivate.h" 59#include "EAPOLSocket.h" 60#include "Supplicant.h" 61#include "myCFUtil.h" 62#include "mylog.h" 63#include "EAPOLControlPrefs.h" 64 65extern EAPClientPluginFuncRef 66md5_introspect(EAPClientPluginFuncName name); 67 68extern EAPClientPluginFuncRef 69eaptls_introspect(EAPClientPluginFuncName name); 70 71extern EAPClientPluginFuncRef 72eapttls_introspect(EAPClientPluginFuncName name); 73 74extern EAPClientPluginFuncRef 75peap_introspect(EAPClientPluginFuncName name); 76 77extern EAPClientPluginFuncRef 78eapmschapv2_introspect(EAPClientPluginFuncName name); 79 80extern EAPClientPluginFuncRef 81eapgtc_introspect(EAPClientPluginFuncName name); 82 83extern EAPClientPluginFuncRef 84eapfast_introspect(EAPClientPluginFuncName name); 85 86extern EAPClientPluginFuncRef 87eapsim_introspect(EAPClientPluginFuncName name); 88 89extern EAPClientPluginFuncRef 90eapaka_introspect(EAPClientPluginFuncName name); 91 92typedef struct { 93 EAPClientPluginFuncIntrospect * introspect_func; 94 const char * name; 95} BuiltinEAPModule; 96 97typedef BuiltinEAPModule const * BuiltinEAPModuleRef; 98 99static const BuiltinEAPModule S_builtin_modules[] = { 100 { md5_introspect, "md5" }, 101 { eaptls_introspect, "eaptls" }, 102 { eapttls_introspect, "eapttls" }, 103 { peap_introspect, "peap" }, 104 { eapmschapv2_introspect, "eapmschapv2" }, 105 { eapgtc_introspect, "eapgtc" }, 106 { eapfast_introspect, "eapfast" }, 107 { eapsim_introspect, "eapsim" }, 108 { eapaka_introspect, "eapaka" } 109}; 110 111EAPClientModuleStatus 112S_load_modules() 113{ 114 int i; 115 BuiltinEAPModuleRef scan; 116 117 for (i = 0, scan = S_builtin_modules; 118 i < (sizeof(S_builtin_modules) / sizeof(S_builtin_modules[0])); 119 i++, scan++) { 120 EAPClientModuleStatus status; 121 122 status = EAPClientModuleAddBuiltinModule(scan->introspect_func); 123 if (status != kEAPClientModuleStatusOK) { 124 EAPLOG_FL(LOG_NOTICE, "EAPClientAddBuiltinModule(%s) failed %d", 125 scan->name, status); 126 return (status); 127 } 128 } 129 return (kEAPClientModuleStatusOK); 130} 131 132static void 133usage(char * progname) 134{ 135 fprintf(stderr, "usage:\n" 136 "%s -i <if_name> [ -u <uid> ] [ -g <gid> ]\n", 137 progname); 138 exit(EX_USAGE); 139} 140 141static void 142log_then_exit(int exit_code) 143{ 144 eapolclient_log(kLogFlagBasic, "exit"); 145 exit(exit_code); 146 return; 147} 148 149static uint32_t 150check_prefs_common(SCPreferencesRef prefs, bool log_it) 151{ 152 uint32_t log_flags; 153 154 log_flags = EAPOLControlPrefsGetLogFlags(); 155 eapolclient_log_set_flags(log_flags, log_it); 156 if (prefs == NULL) { 157 return (log_flags); 158 } 159 EAPOLSocketSetGlobals(prefs); 160 Supplicant_set_globals(prefs); 161 EAPOLControlPrefsSynchronize(); 162 return (log_flags); 163} 164 165static void 166check_prefs(SCPreferencesRef prefs) 167{ 168 check_prefs_common(prefs, TRUE); 169 return; 170} 171 172int 173main(int argc, char * argv[1]) 174{ 175 char ch; 176 CFDictionaryRef config_dict = NULL; 177 char * config_file = NULL; 178 CFDictionaryRef control_dict = NULL; 179 bool g_flag = FALSE; 180 gid_t gid = -1; 181 char * if_name = NULL; 182 LinkAddressesRef link_addrs = NULL; 183 struct sockaddr_dl * link = NULL; 184 uint32_t log_flags = 0; 185 SCPreferencesRef prefs; 186 EAPOLSocketSourceRef source; 187 SupplicantRef supp = NULL; 188 bool u_flag = FALSE; 189 uid_t uid = -1; 190 191 while ((ch = getopt(argc, argv, "c:g:i:lu:")) != EOF) { 192 switch ((char) ch) { 193 case 'c': 194 config_file = optarg; 195 break; 196 case 'i': 197 if (if_name != NULL) { 198 usage(argv[0]); 199 } 200 if_name = optarg; 201 break; 202 case 'u': 203 if (u_flag) { 204 usage(argv[0]); 205 } 206 uid = (uid_t)strtoul(optarg, NULL, 0); 207 u_flag = TRUE; 208 break; 209 case 'g': 210 if (g_flag) { 211 usage(argv[0]); 212 } 213 gid = (gid_t)strtoul(optarg, NULL, 0); 214 g_flag = TRUE; 215 break; 216 default: 217 usage(argv[0]); 218 break; 219 } 220 } 221 if ((argc - optind) != 0 || if_name == NULL) { 222 usage(argv[0]); 223 } 224 if (uid == -1) { 225 uid = getuid(); 226 } 227 if (gid == -1) { 228 gid = getgid(); 229 } 230 openlog("eapolclient", LOG_CONS | LOG_PID, LOG_DAEMON); 231 prefs = EAPOLControlPrefsInit(CFRunLoopGetCurrent(), check_prefs); 232 log_flags = check_prefs_common(prefs, FALSE); 233 if (log_flags == 0) { 234 EAPLOG(LOG_NOTICE, "%s START uid %d gid %d", if_name, uid, gid); 235 } 236 else { 237 EAPLOG(LOG_NOTICE, "%s START uid %d gid %d", if_name, uid, gid); 238 EAPLOG(LOG_NOTICE, "Verbose mode enabled (LogFlags 0x%x)", log_flags); 239 } 240 link_addrs = LinkAddresses_create(); 241 if (link_addrs == NULL) { 242 EAPLOG_FL(LOG_NOTICE, "Could not build interface list"); 243 exit(EX_OSERR); 244 } 245 link = LinkAddresses_lookup(link_addrs, if_name); 246 if (link == NULL) { 247 EAPLOG(LOG_NOTICE, "interface '%s' does not exist", if_name); 248 exit(EX_CONFIG); 249 } 250 if (link->sdl_type != IFT_ETHER) { 251 EAPLOG(LOG_NOTICE, "interface '%s' is not ethernet", if_name); 252 exit(EX_CONFIG); 253 } 254 source = EAPOLSocketSourceCreate(if_name, 255 (const struct ether_addr *) 256 (link->sdl_data + link->sdl_nlen), 257 &control_dict); 258 if (source == NULL) { 259 EAPLOG_FL(LOG_NOTICE, "EAPOLSocketSourceCreate(%s) failed", if_name); 260 log_then_exit(EX_UNAVAILABLE); 261 } 262 if (g_flag) { 263 if (setgid(gid) < 0) { 264 EAPLOG_FL(LOG_NOTICE, "setgid(%d) failed, %s", gid, 265 strerror(errno)); 266 log_then_exit(EX_NOPERM); 267 } 268 } 269 if (u_flag) { 270 if (setuid(uid) < 0) { 271 EAPLOG_FL(LOG_NOTICE, "setuid(%d) failed, %s", uid, 272 strerror(errno)); 273 log_then_exit(EX_NOPERM); 274 } 275 } 276 if (config_file != NULL) { 277 if (control_dict != NULL) { 278 fprintf(stderr, "Ignoring -c %s\n", config_file); 279 } 280 else { 281 config_dict = (CFDictionaryRef) 282 my_CFPropertyListCreateFromFile(config_file); 283 if (isA_CFDictionary(config_dict) == NULL) { 284 fprintf(stderr, 285 "contents of file %s invalid\n", config_file); 286 my_CFRelease(&config_dict); 287 log_then_exit(EX_CONFIG); 288 } 289 } 290 } 291 if (config_dict == NULL && control_dict == NULL) { 292 EAPLOG_FL(LOG_NOTICE, "%s: config/control dictionary missing", if_name); 293 log_then_exit(EX_SOFTWARE); 294 } 295 if (S_load_modules() != kEAPClientModuleStatusOK) { 296 log_then_exit(EX_SOFTWARE); 297 } 298 supp = EAPOLSocketSourceCreateSupplicant(source, control_dict); 299 if (supp == NULL) { 300 EAPLOG_FL(LOG_NOTICE, "EAPOLSocketSourceCreateSupplicant failed"); 301 EAPOLSocketSourceFree(&source); 302 log_then_exit(EX_UNAVAILABLE); 303 } 304 if (control_dict != NULL) { 305 (void)setsid(); 306 (void)chdir("/"); 307 } 308 else { 309 bool should_stop = FALSE; 310 311 (void)Supplicant_update_configuration(supp, config_dict, &should_stop); 312 EAPLOG(LOG_NOTICE, 313 "Supplicant_update_configuration says we should stop - exiting"); 314 exit(EX_UNAVAILABLE); 315 } 316 my_CFRelease(&control_dict); 317 my_CFRelease(&config_dict); 318 Supplicant_start(supp); 319 320 LinkAddresses_free(&link_addrs); 321 CFRunLoopRun(); 322 323 log_then_exit(EX_OK); 324 return (0); 325} 326