1/*
2 * Copyright (c) 2000, 2014 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/* -----------------------------------------------------------------------------
25includes
26----------------------------------------------------------------------------- */
27
28#include <fcntl.h>
29#include <unistd.h>
30#include <netdb.h>
31#include <netdb_async.h>
32#include <sys/param.h>
33#include <sys/socket.h>
34#include <sys/ioctl.h>
35#include "sys/syslog.h"
36#include <paths.h>
37#include <net/if.h>
38#include <net/if_media.h>
39#include <net/ndrv.h>
40#include <net/if_dl.h>
41#include <net/if_utun.h>
42#include <netinet/ip.h>
43#include <netinet/ip_icmp.h>
44#include <arpa/inet.h>
45#include <net/route.h>
46#include <mach/mach_time.h>
47#include <mach/mach.h>
48#include <mach/message.h>
49#include <mach/boolean.h>
50#include <mach/mach_error.h>
51#include <servers/bootstrap.h>
52#include <notify.h>
53#include <sys/kern_control.h>
54#include <sys/sys_domain.h>
55#include <netinet/in_var.h>
56#include <ifaddrs.h>
57#include <sys/sysctl.h>
58
59#include <CoreFoundation/CFUserNotification.h>
60#include <SystemConfiguration/SystemConfiguration.h>
61#include <SystemConfiguration/SCDPlugin.h>
62#include <SystemConfiguration/SCPrivate.h>      // for SCLog()
63#include <mach/task_special_ports.h>
64#include "pppcontroller_types.h"
65#include "pppcontroller.h"
66#include <SystemConfiguration/SCValidation.h>
67#include <SystemConfiguration/SCPreferences.h>
68#include <sys/un.h>
69
70#include "scnc_client.h"
71#include "scnc_main.h"
72#include "ipsec_manager.h"
73#include "ipsec_utils.h"
74#include "scnc_utils.h"
75#include "scnc_cache.h"
76#include "cf_utils.h"
77#include "PPPControllerPriv.h"
78#include "controller_options.h"
79
80//#include <IPSec/IPSec.h>
81//#include <IPSec/IPSecSchemaDefinitions.h>
82
83#include "../Helpers/vpnd/RASSchemaDefinitions.h"
84#include "../Helpers/vpnd/ipsec_utils.h"
85
86#include "sessionTracer.h"
87
88
89
90/* -----------------------------------------------------------------------------
91globals
92----------------------------------------------------------------------------- */
93
94enum {
95    do_nothing = 0,
96    do_process,
97    do_close,
98    do_error
99};
100
101enum {
102	dialog_default_type = 0,
103	dialog_has_disconnect_type = 1,
104	dialog_cert_fixme_type = 2
105};
106
107#define TIMEOUT_INITIAL_CONTACT	10 /* give 10 second to establish contact with server */
108#define TIMEOUT_PHASE1			30 /* give 30 second to complete phase 1 */
109#define TIMEOUT_PHASE2			30 /* give 30 second to complete phase 2 (to accomodate larger cfgs on slower devices) */
110#define TIMEOUT_PHASE2_PING		1 /* sends ping every second until phase 2 starts */
111#define TIMEOUT_ASSERT_IDLE		3 /* allow 3 seconds after assert for traffic to trigger rekeys */
112
113#define MAX_PHASE2_PING			15 /* give up after 15 pings */
114
115#define TIMEOUT_INTERFACE_CHANGE	20 /* give 20 second to address to come back */
116
117#define XAUTH_FIRST_TIME		0x8000
118#define XAUTH_NEED_USERNAME		0x0001
119#define XAUTH_NEED_PASSWORD		0x0002
120#define XAUTH_NEED_PASSCODE		0x0004
121#define XAUTH_NEED_ANSWER		0x0008
122#define XAUTH_NEED_NEXT_PIN		0x0010
123#define XAUTH_NEED_XAUTH_INFO	0x0020
124#define XAUTH_MUST_PROMPT		0x0040
125#define XAUTH_DID_PROMPT		0x0080
126
127#define DISPLAY_RE_ENROLL_ALERT_INTERVAL	15*60	/* how much should lapse before displaying re-enroll alert again */
128
129#define IPSEC_STATUS_IS_CLIENT_CERTIFICATE_INVALID(s) ((s == IPSEC_CLIENT_CERTIFICATE_PREMATURE) || \
130														(s == IPSEC_CLIENT_CERTIFICATE_EXPIRED) ||  \
131														(s == IPSEC_CLIENT_CERTIFICATE_ERROR))
132
133struct isakmp_xauth {
134	u_int16_t	type;
135	CFStringRef str;
136};
137
138
139#if TARGET_OS_EMBEDDED
140// extra CFUserNotification keys
141static CFStringRef const SBUserNotificationTextAutocapitalizationType = CFSTR("SBUserNotificationTextAutocapitalizationType");
142static CFStringRef const SBUserNotificationTextAutocorrectionType = CFSTR("SBUserNotificationTextAutocorrectionType");
143static CFStringRef const SBUserNotificationGroupsTextFields = CFSTR("SBUserNotificationGroupsTextFields");
144#endif
145
146/* -----------------------------------------------------------------------------
147Forward declarations
148----------------------------------------------------------------------------- */
149
150static void ipsec_log(int level, CFStringRef format, ...) CF_FORMAT_FUNCTION(2, 3);
151static void ipsec_updatephase(struct service *serv, int phase);
152static void display_notification(struct service *serv, CFStringRef message, int errnum, int dialog_type);
153static void racoon_timer(CFRunLoopTimerRef timer, void *info);
154static int racoon_restart(struct service *serv, struct sockaddr_in *address);
155static int racoon_resolve(struct service *serv);
156static bool mode_config_is_default(struct service *serv);
157static void install_mode_config(struct service *serv, Boolean installConfig, Boolean installPolicies);
158static void uninstall_mode_config(struct service *serv, Boolean uninstallPolicies);
159static int unassert_mode_config(struct service *serv);
160static int ask_user_xauth(struct service *serv, char* message);
161static boolean_t checkpassword(struct service *serv, int must_prompt);
162int readn(int ref, void *data, int len);
163int writen(int ref, void *data, int len);
164
165int racoon_send_cmd_start_ph2(int fd, u_int32_t address, CFDictionaryRef ipsec_dict);
166int racoon_send_cmd_assert(struct service *serv);
167int racoon_send_cmd_xauthinfo(int fd, u_int32_t address, struct isakmp_xauth *isakmp_array, int isakmp_nb);
168int racoon_send_cmd_start_dpd(int fd, u_int32_t address) ;
169
170void
171ipsec_log(int level, CFStringRef format, ...)
172{
173	if (ne_sm_bridge_is_logging_at_level(level)) {
174		va_list args;
175		va_start(args, format);
176		if (!ne_sm_bridge_logv(level, format, args)) {
177			SCLoggerVLog(NULL, level, format, args);
178		}
179		va_end(args);
180	}
181}
182
183
184/* -----------------------------------------------------------------------------
185 ----------------------------------------------------------------------------- */
186int ipsec_init_things()
187{
188
189    // TO DO: save each configuration and remove them upon configd restart,
190    // in case they are leftover after a crash.
191
192#if TARGET_OS_EMBEDDED
193    // currently only VPN uses IPSec on embedded
194    // Do not flush SAs, so as to not interfere with other configurations
195    //IPSecFlushAll();
196#endif /* TARGET_OS_EMBEDDED */
197
198    return 0;
199}
200
201/* -----------------------------------------------------------------------------
202get the ipsec string corresponding to the ike error
203----------------------------------------------------------------------------- */
204char *ipsec_error_to_str(int ike_code)
205{
206	switch (ike_code) {
207		case VPNCTL_NTYPE_INVALID_PAYLOAD_TYPE: return "Invalid payload type";
208		case VPNCTL_NTYPE_DOI_NOT_SUPPORTED: return "DOI not supported";
209		case VPNCTL_NTYPE_SITUATION_NOT_SUPPORTED: return "Situation not supported";
210		case VPNCTL_NTYPE_INVALID_COOKIE: return "Invalid cookie";
211		case VPNCTL_NTYPE_INVALID_MAJOR_VERSION: return "Invalid major version";
212		case VPNCTL_NTYPE_INVALID_MINOR_VERSION: return "Invalid minor version";
213		case VPNCTL_NTYPE_INVALID_EXCHANGE_TYPE: return "Invalid exchange type";
214		case VPNCTL_NTYPE_INVALID_FLAGS: return "Invalid flags";
215		case VPNCTL_NTYPE_INVALID_MESSAGE_ID: return "Invalid message id";
216		case VPNCTL_NTYPE_INVALID_PROTOCOL_ID: return "Invalid protocol id";
217		case VPNCTL_NTYPE_INVALID_SPI: return "Invalid SPI";
218		case VPNCTL_NTYPE_INVALID_TRANSFORM_ID: return "Invalid transform id";
219		case VPNCTL_NTYPE_ATTRIBUTES_NOT_SUPPORTED: return "Attributes not supported";
220		case VPNCTL_NTYPE_NO_PROPOSAL_CHOSEN: return "No proposal chosen";
221		case VPNCTL_NTYPE_BAD_PROPOSAL_SYNTAX: return "Bad proposal syntax";
222		case VPNCTL_NTYPE_PAYLOAD_MALFORMED: return "Payload malformed";
223		case VPNCTL_NTYPE_INVALID_KEY_INFORMATION: return "Invalid key information";
224		case VPNCTL_NTYPE_INVALID_ID_INFORMATION: return "Invalid id information";
225		case VPNCTL_NTYPE_INVALID_CERT_ENCODING: return "Invalid cert encoding";
226		case VPNCTL_NTYPE_INVALID_CERTIFICATE: return "Invalid certificate";
227		case VPNCTL_NTYPE_BAD_CERT_REQUEST_SYNTAX: return "Bad cert request syntax";
228		case VPNCTL_NTYPE_INVALID_CERT_AUTHORITY: return "Invalid cert authority";
229		case VPNCTL_NTYPE_INVALID_HASH_INFORMATION: return "Invalid hash information";
230		case VPNCTL_NTYPE_AUTHENTICATION_FAILED: return "Authentication Failed";
231		case VPNCTL_NTYPE_INVALID_SIGNATURE: return "Invalid signature";
232		case VPNCTL_NTYPE_ADDRESS_NOTIFICATION: return "Address notification";
233		case VPNCTL_NTYPE_NOTIFY_SA_LIFETIME: return "Notify SA lifetime";
234		case VPNCTL_NTYPE_CERTIFICATE_UNAVAILABLE: return "Certificate unavailable";
235		case VPNCTL_NTYPE_UNSUPPORTED_EXCHANGE_TYPE: return "Unsupported exchange type";
236		case VPNCTL_NTYPE_UNEQUAL_PAYLOAD_LENGTHS: return "Unequal payload lengths";
237		case VPNCTL_NTYPE_LOAD_BALANCE: return "Load balance";
238		case VPNCTL_NTYPE_PEER_DEAD: return "Dead Peer";
239		case VPNCTL_NTYPE_PH1_DELETE: return "Phase 1 Delete";
240		case VPNCTL_NTYPE_IDLE_TIMEOUT: return "Idle Timeout";
241		case VPNCTL_NTYPE_LOCAL_CERT_PREMATURE: return "Certificate premature";
242		case VPNCTL_NTYPE_LOCAL_CERT_EXPIRED: return "Certificate expired";
243		case VPNCTL_NTYPE_PEER_CERT_PREMATURE: return "Server certificate premature";
244		case VPNCTL_NTYPE_PEER_CERT_EXPIRED: return "Server certificate expired";
245		case VPNCTL_NTYPE_PEER_CERT_INVALID_SUBJNAME: return "Server certificate subjectName invalid";
246		case VPNCTL_NTYPE_PEER_CERT_INVALID_SUBJALTNAME: return "Server certificate subjectAltName invalid";
247		case VPNCTL_NTYPE_INTERNAL_ERROR: return "Internal error";
248	}
249	return "Unknown error";
250}
251
252/* -----------------------------------------------------------------------------
253get the ipsec generic error corresponding to the ike error
254----------------------------------------------------------------------------- */
255u_int32_t ipsec_error_to_status(struct service *serv, int from, int ike_code)
256{
257	switch (ike_code) {
258		case VPNCTL_NTYPE_INVALID_PAYLOAD_TYPE:
259		case VPNCTL_NTYPE_DOI_NOT_SUPPORTED:
260		case VPNCTL_NTYPE_SITUATION_NOT_SUPPORTED:
261		case VPNCTL_NTYPE_INVALID_COOKIE:
262		case VPNCTL_NTYPE_INVALID_MAJOR_VERSION:
263		case VPNCTL_NTYPE_INVALID_MINOR_VERSION:
264		case VPNCTL_NTYPE_INVALID_EXCHANGE_TYPE:
265		case VPNCTL_NTYPE_INVALID_FLAGS:
266		case VPNCTL_NTYPE_INVALID_MESSAGE_ID:
267		case VPNCTL_NTYPE_INVALID_PROTOCOL_ID:
268		case VPNCTL_NTYPE_INVALID_SPI:
269		case VPNCTL_NTYPE_INVALID_TRANSFORM_ID:
270		case VPNCTL_NTYPE_ATTRIBUTES_NOT_SUPPORTED:
271		case VPNCTL_NTYPE_NO_PROPOSAL_CHOSEN:
272		case VPNCTL_NTYPE_BAD_PROPOSAL_SYNTAX:
273		case VPNCTL_NTYPE_PAYLOAD_MALFORMED:
274		case VPNCTL_NTYPE_INVALID_KEY_INFORMATION:
275		case VPNCTL_NTYPE_INVALID_ID_INFORMATION:
276		case VPNCTL_NTYPE_INVALID_CERT_ENCODING:
277		case VPNCTL_NTYPE_BAD_CERT_REQUEST_SYNTAX:
278		case VPNCTL_NTYPE_UNSUPPORTED_EXCHANGE_TYPE:
279		case VPNCTL_NTYPE_UNEQUAL_PAYLOAD_LENGTHS:
280		case VPNCTL_NTYPE_INTERNAL_ERROR:
281			return IPSEC_NEGOTIATION_ERROR;
282
283		case VPNCTL_NTYPE_INVALID_HASH_INFORMATION:
284			return IPSEC_SHAREDSECRET_ERROR;
285
286		case VPNCTL_NTYPE_CERTIFICATE_UNAVAILABLE:
287			return IPSEC_NOCERTIFICATE_ERROR;
288
289		case VPNCTL_NTYPE_INVALID_SIGNATURE:
290		case VPNCTL_NTYPE_INVALID_CERTIFICATE:
291		case VPNCTL_NTYPE_INVALID_CERT_AUTHORITY:
292			return (from == FROM_REMOTE ? IPSEC_CLIENT_CERTIFICATE_ERROR : IPSEC_SERVER_CERTIFICATE_ERROR);
293
294		case VPNCTL_NTYPE_AUTHENTICATION_FAILED:
295			return IPSEC_XAUTH_ERROR;
296
297		case VPNCTL_NTYPE_ADDRESS_NOTIFICATION:
298		case VPNCTL_NTYPE_NOTIFY_SA_LIFETIME:
299		case VPNCTL_NTYPE_LOAD_BALANCE:
300		case VPNCTL_NTYPE_PEER_DEAD:
301		case VPNCTL_NTYPE_IDLE_TIMEOUT:
302			return IPSEC_NO_ERROR;
303
304		case VPNCTL_NTYPE_PH1_DELETE:
305			return IPSEC_NO_ERROR;
306
307		case VPNCTL_NTYPE_LOCAL_CERT_PREMATURE:
308			return IPSEC_CLIENT_CERTIFICATE_PREMATURE;
309
310		case VPNCTL_NTYPE_LOCAL_CERT_EXPIRED:
311			return IPSEC_CLIENT_CERTIFICATE_EXPIRED;
312
313		case VPNCTL_NTYPE_PEER_CERT_PREMATURE:
314			return IPSEC_SERVER_CERTIFICATE_PREMATURE;
315
316		case VPNCTL_NTYPE_PEER_CERT_EXPIRED:
317			return IPSEC_SERVER_CERTIFICATE_EXPIRED;
318
319		case VPNCTL_NTYPE_PEER_CERT_INVALID_SUBJNAME:
320		case VPNCTL_NTYPE_PEER_CERT_INVALID_SUBJALTNAME:
321			return IPSEC_SERVER_CERTIFICATE_INVALID_ID;
322
323	}
324	return IPSEC_GENERIC_ERROR;
325}
326
327/* -----------------------------------------------------------------------------
328get the ipsec string corresponding to the message type
329----------------------------------------------------------------------------- */
330char *ipsec_msgtype_to_str(int msgtype)
331{
332	switch (msgtype) {
333		case VPNCTL_CMD_BIND: return "VPNCTL_CMD_BIND";
334		case VPNCTL_CMD_UNBIND: return "VPNCTL_CMD_UNBIND";
335		case VPNCTL_CMD_REDIRECT: return "VPNCTL_CMD_REDIRECT";
336		case VPNCTL_CMD_PING: return "VPNCTL_CMD_PING";
337		case VPNCTL_CMD_CONNECT: return "VPNCTL_CMD_CONNECT";
338		case VPNCTL_CMD_DISCONNECT: return "VPNCTL_CMD_DISCONNECT";
339		case VPNCTL_CMD_START_PH2: return "VPNCTL_CMD_START_PH2";
340		case VPNCTL_CMD_XAUTH_INFO: return "VPNCTL_CMD_XAUTH_INFO";
341		case VPNCTL_CMD_ASSERT: return "VPNCTL_CMD_ASSERT";
342		case VPNCTL_CMD_RECONNECT: return "VPNCTL_CMD_RECONNECT";
343		case VPNCTL_STATUS_IKE_FAILED: return "VPNCTL_STATUS_IKE_FAILED";
344		case VPNCTL_STATUS_PH1_START_US: return "VPNCTL_STATUS_PH1_START_US";
345		case VPNCTL_STATUS_PH1_START_PEER: return "VPNCTL_STATUS_PH1_START_PEER";
346		case VPNCTL_STATUS_PH1_ESTABLISHED: return "VPNCTL_STATUS_PH1_ESTABLISHED";
347		case VPNCTL_STATUS_PH2_START: return "VPNCTL_STATUS_PH2_START";
348		case VPNCTL_STATUS_PH2_ESTABLISHED: return "VPNCTL_STATUS_PH2_ESTABLISHED";
349		case VPNCTL_STATUS_NEED_AUTHINFO: return "VPNCTL_STATUS_NEED_AUTHINFO";
350		case VPNCTL_STATUS_NEED_REAUTHINFO: return "VPNCTL_STATUS_NEED_REAUTHINFO";
351	}
352	return "Unknown message type";
353}
354
355/* -----------------------------------------------------------------------------
356get the ipsec string corresponding to the message type
357----------------------------------------------------------------------------- */
358char *ipsec_xauthtype_to_str(int msgtype)
359{
360	switch (msgtype) {
361		case XAUTH_TYPE: return "XAUTH_TYPE";
362		case XAUTH_USER_NAME: return "XAUTH_USER_NAME";
363		case XAUTH_USER_PASSWORD: return "XAUTH_USER_PASSWORD";
364		case XAUTH_PASSCODE: return "XAUTH_PASSCODE";
365		case XAUTH_MESSAGE: return "XAUTH_MESSAGE";
366		case XAUTH_CHALLENGE: return "XAUTH_CHALLENGE";
367		case XAUTH_DOMAIN: return "XAUTH_DOMAIN";
368		case XAUTH_STATUS: return "XAUTH_STATUS";
369		case XAUTH_NEXT_PIN: return "XAUTH_NEXT_PIN";
370		case XAUTH_ANSWER: return "XAUTH_ANSWER";
371	}
372	return "XAUTH_TYPE unknown type";
373}
374
375/* -----------------------------------------------------------------------------
376get the ipsec string corresponding to the message type
377----------------------------------------------------------------------------- */
378char *ipsec_modecfgtype_to_str(int msgtype)
379{
380	switch (msgtype) {
381
382		case INTERNAL_IP4_ADDRESS: return "INTERNAL_IP4_ADDRESS";
383		case INTERNAL_IP4_NETMASK: return "INTERNAL_IP4_NETMASK";
384		case INTERNAL_IP4_DNS: return "INTERNAL_IP4_DNS";
385		case INTERNAL_IP4_NBNS: return "INTERNAL_IP4_NBNS";
386		case INTERNAL_ADDRESS_EXPIRY: return "INTERNAL_ADDRESS_EXPIRY";
387		case INTERNAL_IP4_DHCP: return "INTERNAL_IP4_DHCP";
388		case APPLICATION_VERSION: return "APPLICATION_VERSION";
389		case INTERNAL_IP6_ADDRESS: return "INTERNAL_IP6_ADDRESS";
390		case INTERNAL_IP6_NETMASK: return "INTERNAL_IP6_NETMASK";
391		case INTERNAL_IP6_DNS: return "INTERNAL_IP6_DNS";
392		case INTERNAL_IP6_NBNS: return "INTERNAL_IP6_NBNS";
393		case INTERNAL_IP6_DHCP: return "INTERNAL_IP6_DHCP";
394		case INTERNAL_IP4_SUBNET: return "INTERNAL_IP4_SUBNET";
395		case SUPPORTED_ATTRIBUTES: return "SUPPORTED_ATTRIBUTES";
396		case INTERNAL_IP6_SUBNET: return "INTERNAL_IP6_SUBNET";
397
398	}
399	return "MODECFG_TYPE unknown type";
400}
401
402
403/* -----------------------------------------------------------------------------
404----------------------------------------------------------------------------- */
405u_int16_t ipsec_subtype(CFStringRef subtypeRef)
406{
407
408	return 0;
409}
410
411/* -----------------------------------------------------------------------------
412an interface structure needs to be created
413----------------------------------------------------------------------------- */
414int ipsec_new_service(struct service *serv)
415{
416
417    serv->u.ipsec.phase = IPSEC_IDLE;
418    serv->u.ipsec.controlfd = -1;
419	serv->u.ipsec.kernctl_sock = -1;
420    serv->u.ipsec.eventfd = -1;
421	serv->u.ipsec.routes = NULL;
422    return 0;
423}
424
425/* -----------------------------------------------------------------------------
426an interface is come down, dispose the structure
427----------------------------------------------------------------------------- */
428int ipsec_dispose_service(struct service *serv)
429{
430
431    if (serv->u.ipsec.phase != IPSEC_IDLE)
432        return 1;
433    free_service_routes(serv);
434	my_CFRelease(&serv->systemprefs);
435    return 0;
436}
437
438/* -----------------------------------------------------------------------------
439changed for this service occured in configd cache
440----------------------------------------------------------------------------- */
441int ipsec_setup_service(struct service *serv)
442{
443
444    u_int32_t 		lval;
445
446	/* get some general setting flags first */
447	serv->flags &= ~(
448					 FLAG_SETUP_ONTRAFFIC +
449					 FLAG_SETUP_DISCONNECTONLOGOUT +
450					 FLAG_SETUP_DISCONNECTONSLEEP +
451					 FLAG_SETUP_PREVENTIDLESLEEP +
452					 FLAG_SETUP_DISCONNECTONFASTUSERSWITCH +
453					 FLAG_SETUP_ONDEMAND +
454					 FLAG_DARKWAKE +
455					 FLAG_SETUP_PERSISTCONNECTION +
456					 FLAG_SETUP_DISCONNECTONWAKE);
457
458	serv->flags |= (
459					FLAG_ALERTERRORS +
460					FLAG_ALERTPASSWORDS);
461
462	my_CFRelease(&serv->systemprefs);
463	if (serv->ne_sm_bridge != NULL) {
464		serv->systemprefs = ne_sm_bridge_copy_configuration(serv->ne_sm_bridge);
465	} else {
466		serv->systemprefs = copyEntity(gDynamicStore, kSCDynamicStoreDomainSetup, serv->serviceID, kSCEntNetIPSec);
467	}
468	if (serv->systemprefs == NULL) {
469		ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Cannot copy IPSec dictionary from setup"));
470		ipsec_stop(serv, 0);
471		return -1;
472	}
473
474	/* Currently, OnDemand imples network detection */
475	lval = 0;
476	getNumber(serv->systemprefs, kSCPropNetIPSecOnDemandEnabled, &lval);
477	if (lval)
478		serv->flags |= (FLAG_SETUP_ONDEMAND | FLAG_SETUP_NETWORKDETECTION);
479	else if (CFDictionaryGetValue(serv->systemprefs, kSCPropNetVPNOnDemandRules)) {
480		if (controller_options_is_useVODDisconnectRulesWhenVODDisabled())
481			serv->flags |= FLAG_SETUP_NETWORKDETECTION;
482	}
483
484	lval = 0;
485	getNumber(serv->systemprefs, CFSTR("DisconnectOnLogout"), &lval);
486	if (lval) serv->flags |= FLAG_SETUP_DISCONNECTONLOGOUT;
487
488	lval = 0;
489	getNumber(serv->systemprefs, CFSTR("DisconnectOnSleep"), &lval);
490	if (lval) serv->flags |= FLAG_SETUP_DISCONNECTONSLEEP;
491
492	lval = 0;
493	getNumber(serv->systemprefs, CFSTR("PreventIdleSleep"), &lval);
494	if (lval) serv->flags |= FLAG_SETUP_PREVENTIDLESLEEP;
495
496	/* if the DisconnectOnFastUserSwitch key does not exist, use DisconnectOnLogout */
497	lval = (serv->flags & FLAG_SETUP_DISCONNECTONLOGOUT);
498	getNumber(serv->systemprefs, CFSTR("DisconnectOnFastUserSwitch"), &lval);
499	if (lval) serv->flags |= FLAG_SETUP_DISCONNECTONFASTUSERSWITCH;
500
501	/* "disconnect on wake" is enabled by default for IPSec */
502	lval = 1;
503	serv->sleepwaketimeout = 0;
504	getNumber(serv->systemprefs, kSCPropNetIPSecDisconnectOnWake, &lval);
505	if (lval) {
506		serv->flags |= FLAG_SETUP_DISCONNECTONWAKE;
507		getNumber(serv->systemprefs, kSCPropNetIPSecDisconnectOnWakeTimer, &serv->sleepwaketimeout);
508	}
509
510	lval = 1;
511	getNumber(serv->systemprefs, CFSTR("AlertEnable"), &lval);
512	if (!lval) serv->flags &= ~(FLAG_ALERTERRORS + FLAG_ALERTPASSWORDS);
513
514	/* enable "ConnectionPersist" */
515	lval = 0;
516	getNumber(serv->systemprefs, CFSTR("ConnectionPersist"), &lval);
517	if (lval) serv->flags |= FLAG_SETUP_PERSISTCONNECTION;
518
519#if TARGET_OS_EMBEDDED
520	if (CFDictionaryContainsKey(serv->systemprefs, CFSTR("ProfileIdentifier"))) {
521		my_CFRelease(&serv->profileIdentifier);
522		serv->profileIdentifier = my_CFRetain(CFDictionaryGetValue(serv->systemprefs, CFSTR("ProfileIdentifier")));
523	}
524#endif
525
526	return 0;
527}
528
529/* -----------------------------------------------------------------------------
530----------------------------------------------------------------------------- */
531static void merge_ipsec_dict(const void *key, const void *value, void *context)
532{
533	/* ignore some of the keys */
534
535	/* remote address was resolved elsewhere */
536	if (CFStringCompare(key, kRASPropIPSecRemoteAddress, 0) == kCFCompareEqualTo)
537		return;
538
539	/* merge everything else */
540	CFDictionarySetValue((CFMutableDictionaryRef)context, key, value);
541}
542
543/* -----------------------------------------------------------------------------
544----------------------------------------------------------------------------- */
545void ipsec_user_notification_callback(struct service *serv, CFUserNotificationRef userNotification, CFOptionFlags responseFlags)
546{
547
548	if ((responseFlags & 3) != kCFUserNotificationDefaultResponse) {
549		switch (serv->u.ipsec.phase) {
550			case IPSEC_IDLE:
551				if (IPSEC_STATUS_IS_CLIENT_CERTIFICATE_INVALID(serv->u.ipsec.laststatus)) {
552#if TARGET_OS_EMBEDDED
553					if (serv->ne_sm_bridge) {
554						ne_sm_bridge_start_profile_janitor(serv->ne_sm_bridge, serv->profileIdentifier);
555					} else {
556						start_profile_janitor(serv);
557					}
558#endif
559				}
560				return;
561			default:
562				// user cancelled
563				ipsec_stop(serv, 0);
564				return;
565
566		}
567	}
568
569#if TARGET_OS_EMBEDDED
570	if (serv->u.ipsec.phase != IPSEC_PHASE1AUTH)
571		return;
572#else
573	if (serv->u.ipsec.phase != IPSEC_PHASE1AUTH &&
574	    serv->u.ipsec.phase != IPSEC_RUNNING)
575		return;
576#endif
577
578	struct isakmp_xauth		isakmp_array[2]; /* max 2 attributes currently supported simultaneously */
579	int						isakmp_nb = 0;
580
581	if (serv->u.ipsec.xauth_flags & XAUTH_NEED_ANSWER) {
582		isakmp_array[isakmp_nb].type = XAUTH_ANSWER;
583		isakmp_array[isakmp_nb].str = CFUserNotificationGetResponseValue(userNotification, kCFUserNotificationTextFieldValuesKey, isakmp_nb);
584		isakmp_nb++;
585	}
586	else if (serv->u.ipsec.xauth_flags & XAUTH_NEED_NEXT_PIN) {
587		isakmp_array[isakmp_nb].type = XAUTH_NEXT_PIN;
588		isakmp_array[isakmp_nb].str = CFUserNotificationGetResponseValue(userNotification, kCFUserNotificationTextFieldValuesKey, isakmp_nb);
589		isakmp_nb++;
590	}
591	else {
592		if (serv->u.ipsec.xauth_flags & XAUTH_NEED_USERNAME) {
593			isakmp_array[isakmp_nb].type = XAUTH_USER_NAME;
594			isakmp_array[isakmp_nb].str = CFUserNotificationGetResponseValue(userNotification, kCFUserNotificationTextFieldValuesKey, isakmp_nb);
595			isakmp_nb++;
596		}
597
598		if (serv->u.ipsec.xauth_flags & XAUTH_NEED_PASSCODE) {
599			isakmp_array[isakmp_nb].type = XAUTH_PASSCODE;
600			isakmp_array[isakmp_nb].str = CFUserNotificationGetResponseValue(userNotification, kCFUserNotificationTextFieldValuesKey, isakmp_nb);
601			isakmp_nb++;
602		}
603		else if (serv->u.ipsec.xauth_flags & XAUTH_NEED_PASSWORD) {
604			isakmp_array[isakmp_nb].type = XAUTH_USER_PASSWORD;
605			isakmp_array[isakmp_nb].str = CFUserNotificationGetResponseValue(userNotification, kCFUserNotificationTextFieldValuesKey, isakmp_nb);
606			isakmp_nb++;
607		}
608	}
609
610	// note: isakmp_nb can be 0. for exmple, sometime the server just pushes a message information, and we just need to acknowledge
611#if TARGET_OS_EMBEDDED
612	if (serv->u.ipsec.timerref) {
613		CFRunLoopTimerSetNextFireDate(serv->u.ipsec.timerref, CFAbsoluteTimeGetCurrent() + TIMEOUT_PHASE1);
614	}
615	ipsec_updatephase(serv, IPSEC_PHASE1);
616#else
617	if (serv->u.ipsec.phase == IPSEC_PHASE1AUTH) {
618		if (serv->u.ipsec.timerref) {
619			CFRunLoopTimerSetNextFireDate(serv->u.ipsec.timerref, CFAbsoluteTimeGetCurrent() + TIMEOUT_PHASE1);
620		}
621		ipsec_updatephase(serv, IPSEC_PHASE1);
622	}
623#endif /* TARGET_OS_EMBEDDED */
624	racoon_send_cmd_xauthinfo(serv->u.ipsec.controlfd, serv->u.ipsec.peer_address.sin_addr.s_addr, isakmp_array, isakmp_nb);
625
626}
627
628/* -----------------------------------------------------------------------------
629 ----------------------------------------------------------------------------- */
630static boolean_t checkpassword(struct service *serv, int must_prompt)
631{
632	int pref_must_prompt;
633	Boolean ok;
634	Boolean didrestart = FALSE;
635	Boolean needauthinfo = FALSE;
636
637	pref_must_prompt = (serv->u.ipsec.xauth_flags & XAUTH_MUST_PROMPT) ? 1 : 0;
638	if (must_prompt != pref_must_prompt) {
639		needauthinfo = (serv->u.ipsec.xauth_flags & XAUTH_NEED_XAUTH_INFO) ? TRUE : FALSE;
640
641		if (serv->ne_sm_bridge == NULL) {
642			ok = UpdatePasswordPrefs(serv->serviceID, serv->typeRef, kSCNetworkInterfacePasswordTypeIPSecXAuth,
643			                         kSCPropNetIPSecXAuthPasswordEncryption, must_prompt ? kSCValNetIPSecXAuthPasswordEncryptionPrompt : NULL,
644			                         CFSTR("IPSec Controller"));
645		} else {
646			ne_sm_bridge_clear_saved_password(serv->ne_sm_bridge, kSCPropNetIPSecXAuthPassword);
647			ok = TRUE;
648		}
649
650		if (ok) {
651			// update current config
652			if (must_prompt) {
653				serv->u.ipsec.xauth_flags |= XAUTH_MUST_PROMPT;
654				CFDictionarySetValue(serv->u.ipsec.config, kSCPropNetIPSecXAuthPasswordEncryption, kSCValNetIPSecXAuthPasswordEncryptionPrompt);
655			} else {
656				serv->u.ipsec.xauth_flags &= ~XAUTH_MUST_PROMPT;
657				CFDictionaryRemoveValue( serv->u.ipsec.config, kSCPropNetIPSecXAuthPasswordEncryption);
658			}
659		}
660
661		if ( needauthinfo && (serv->u.ipsec.xauth_flags & XAUTH_MUST_PROMPT)
662			&& !(serv->u.ipsec.xauth_flags & XAUTH_DID_PROMPT)) {
663			/* policy changed from "ok to save" to "do not save"
664			 if the connection was established using a saved password,
665			 then disconnect, and reconnect to make sure the user is prompted */
666
667			racoon_restart(serv, &serv->u.ipsec.peer_address);
668			didrestart = TRUE;
669		}
670	}
671	return didrestart;
672}
673
674/* -----------------------------------------------------------------------------
675 ----------------------------------------------------------------------------- */
676static CFStringRef copy_decrypted_password(struct service *serv)
677{
678#if !TARGET_OS_EMBEDDED
679	SCNetworkInterfaceRef	interface = NULL;
680	SCNetworkServiceRef		service = NULL;
681	SCPreferencesRef		prefs = NULL;
682#endif
683	CFStringRef	decryptedpasswd = NULL;
684	CFStringRef passwdencryption = NULL;
685
686	passwdencryption = CFDictionaryGetValue(serv->u.ipsec.config, kSCPropNetIPSecXAuthPasswordEncryption);
687	passwdencryption = isA_CFString(passwdencryption);
688	if (passwdencryption) {
689		if (CFStringCompare(passwdencryption, kSCValNetIPSecXAuthPasswordEncryptionKeychain, 0) == kCFCompareEqualTo) {
690#if TARGET_OS_EMBEDDED
691			// TO DO:
692			// currently, password is given inline in SCNetworkConnectionStart
693			// needs t implement keychain support later
694#else
695			prefs = SCPreferencesCreate(NULL, CFSTR("CopyPassword"), NULL);
696			if (prefs == NULL) {
697				ipsec_log(LOG_ERR, CFSTR("IPSec Controller: SCPreferencesCreate fails"));
698				goto done;
699			}
700			// get the service
701			service = SCNetworkServiceCopy(prefs, serv->serviceID);
702			if (service == NULL) {
703				ipsec_log(LOG_ERR, CFSTR("IPSec Controller: SCNetworkServiceCopy fails"));
704				goto done;
705			}
706			// get the interface associated with the service
707			interface = SCNetworkServiceGetInterface(service);
708			if ((interface == NULL) || !CFEqual(SCNetworkInterfaceGetInterfaceType(interface), kSCNetworkInterfaceTypeIPSec)) {
709				ipsec_log(LOG_ERR, CFSTR("IPSec Controller: interface not IPSec"));
710				goto done;
711			}
712			CFDataRef passworddata = SCNetworkInterfaceCopyPassword( interface, kSCNetworkInterfacePasswordTypeIPSecXAuth);
713			if (passworddata) {
714				CFIndex passworddatalen = CFDataGetLength(passworddata);
715				if ((decryptedpasswd = CFStringCreateWithBytes(NULL, CFDataGetBytePtr(passworddata), passworddatalen, kCFStringEncodingUTF8, FALSE)))
716					ipsec_log(LOG_INFO, CFSTR("IPSec Controller: decrypted password %s"),  decryptedpasswd ? (CFStringGetCStringPtr(decryptedpasswd,kCFStringEncodingMacRoman)) : "NULL");
717				else
718					ipsec_log(LOG_ERR, CFSTR("IPSec Controller: cannot decrypt password"));
719				CFRelease(passworddata);
720			}
721#endif
722		}
723	}
724	else {
725		decryptedpasswd = CFDictionaryGetValue(serv->u.ipsec.config, kSCPropNetIPSecXAuthPassword);
726		decryptedpasswd = isA_CFString(decryptedpasswd);
727		if (decryptedpasswd)
728			CFRetain(decryptedpasswd);
729	}
730
731#if !TARGET_OS_EMBEDDED
732done:
733	if (prefs != NULL) {
734        CFRelease(prefs);
735	}
736	if (service != NULL) {
737		CFRelease(service);
738	}
739#endif
740	return (CFStringRef)decryptedpasswd;
741}
742
743/* -----------------------------------------------------------------------------
744----------------------------------------------------------------------------- */
745static
746int ask_user_xauth(struct service *serv, char* message)
747{
748    CFStringRef 	msg = NULL;
749    CFMutableDictionaryRef 	dict = NULL;
750    SInt32 			err;
751    CFOptionFlags 		flags;
752    CFMutableArrayRef 		array;
753	CFIndex  secure_field = 0;
754	int		ret = 0;
755#if TARGET_OS_EMBEDDED
756	int		nbfields = 0;
757#endif
758
759    if ((serv->flags & FLAG_ALERTPASSWORDS) == 0)
760        return -1;
761
762#if !TARGET_OS_EMBEDDED
763    if (serv->flags & FLAG_DARKWAKE)
764        return -1;
765#endif
766
767	/* first, remove any pending notification, if any */
768	if (serv->userNotificationRef) {
769		CFUserNotificationCancel(serv->userNotificationRef);
770		CFRunLoopRemoveSource(CFRunLoopGetCurrent(), serv->userNotificationRLS, kCFRunLoopDefaultMode);
771		my_CFRelease(&serv->userNotificationRef);
772		my_CFRelease(&serv->userNotificationRLS);
773	}
774
775	if (message)
776		msg = CFStringCreateWithFormat(0, 0, CFSTR("%s"), message);
777	else
778		msg = CFStringCreateWithFormat(0, 0, CFSTR("Enter your user authentication"));
779
780    if (!msg && !CFStringGetLength(msg))
781		goto fail;
782
783    dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
784    if (!dict)
785		goto fail;
786
787	if (gIconURLRef)
788		CFDictionaryAddValue(dict, kCFUserNotificationIconURLKey, gIconURLRef);
789	if (gBundleURLRef)
790		CFDictionaryAddValue(dict, kCFUserNotificationLocalizationURLKey, gBundleURLRef);
791
792	CFDictionaryAddValue(dict, kCFUserNotificationAlertMessageKey, msg);
793	CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, CFSTR("VPN Connection"));
794	CFDictionaryAddValue(dict, kCFUserNotificationAlternateButtonTitleKey, CFSTR("Cancel"));
795
796	array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
797	if (array) {
798		if (serv->u.ipsec.xauth_flags & XAUTH_NEED_ANSWER) {
799			CFArrayAppendValue(array, CFSTR("Answer"));
800		}
801		else if (serv->u.ipsec.xauth_flags & XAUTH_NEED_NEXT_PIN) {
802			CFArrayAppendValue(array, CFSTR("Next PIN"));
803			secure_field = 1;
804		}
805		else {
806			if (serv->u.ipsec.xauth_flags & XAUTH_NEED_USERNAME) {
807				CFArrayAppendValue(array, CFSTR("Account"));
808			}
809
810			if (serv->u.ipsec.xauth_flags & XAUTH_NEED_PASSCODE) {
811				CFArrayAppendValue(array, CFSTR("Passcode"));
812				secure_field = (serv->u.ipsec.xauth_flags & XAUTH_NEED_USERNAME) ? 2 : 1;
813			}
814			else if (serv->u.ipsec.xauth_flags & XAUTH_NEED_PASSWORD) {
815				CFArrayAppendValue(array, CFSTR("Password"));
816				secure_field = (serv->u.ipsec.xauth_flags & XAUTH_NEED_USERNAME) ? 2 : 1;
817			}
818		}
819
820#if TARGET_OS_EMBEDDED
821		nbfields = CFArrayGetCount(array);
822#endif
823		CFDictionaryAddValue(dict, kCFUserNotificationTextFieldTitlesKey, array);
824		CFRelease(array);
825	}
826
827	if (serv->u.ipsec.xauth_flags & XAUTH_NEED_USERNAME) {
828		CFStringRef username = CFDictionaryGetValue(serv->u.ipsec.config, kRASPropIPSecXAuthName);
829		if (isString(username)) {
830			array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
831			if (array) {
832				CFArrayAppendValue(array, username);
833
834				// for some reason, CFUsernotification wants to have both values present in the array, in order to display the first one.
835				if (serv->u.ipsec.xauth_flags & (XAUTH_NEED_PASSWORD | XAUTH_NEED_PASSCODE)) {
836					CFArrayAppendValue(array, CFSTR(""));
837				}
838
839				CFDictionaryAddValue(dict, kCFUserNotificationTextFieldValuesKey, array);
840				CFRelease(array);
841			}
842		}
843	}
844
845#if TARGET_OS_EMBEDDED
846	if (nbfields > 0) {
847		CFMutableArrayRef autoCapsTypes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
848		CFMutableArrayRef autoCorrectionTypes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
849		int i, zero = 0, one = 1;
850		CFNumberRef zeroRef = CFNumberCreate(NULL, kCFNumberIntType, &zero);
851		CFNumberRef oneRef = CFNumberCreate(NULL, kCFNumberIntType, &one);
852
853		if (autoCapsTypes && autoCorrectionTypes && zeroRef && oneRef) {
854			for(i = 0; i < nbfields; i++) {
855				// no auto caps or autocorrection for any of our fields
856				CFArrayAppendValue(autoCapsTypes, zeroRef);
857				CFArrayAppendValue(autoCorrectionTypes, oneRef);
858			}
859			CFDictionarySetValue(dict, SBUserNotificationTextAutocapitalizationType, autoCapsTypes);
860			CFDictionarySetValue(dict, SBUserNotificationTextAutocorrectionType, autoCorrectionTypes);
861		}
862		my_CFRelease(&autoCapsTypes);
863		my_CFRelease(&autoCorrectionTypes);
864		my_CFRelease(&zeroRef);
865		my_CFRelease(&oneRef);
866
867		// make CFUN prettier
868		CFDictionarySetValue(dict, SBUserNotificationGroupsTextFields, kCFBooleanTrue);
869	}
870#endif
871
872	flags = 0;
873	if (secure_field)
874		flags = CFUserNotificationSecureTextField(secure_field - 1);
875
876	serv->userNotificationRef = CFUserNotificationCreate(NULL, 150 /* 2 min 30 sec */, flags, &err, dict);
877	if (!serv->userNotificationRef)
878		goto fail;
879
880	serv->userNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, serv->userNotificationRef,
881												user_notification_callback, 0);
882	if (!serv->userNotificationRLS) {
883		my_CFRelease(&serv->userNotificationRef);
884		goto fail;
885	}
886	CFRunLoopAddSource(CFRunLoopGetCurrent(), serv->userNotificationRLS, kCFRunLoopDefaultMode);
887
888done:
889    my_CFRelease(&dict);
890    my_CFRelease(&msg);
891	return ret;
892
893fail:
894	ret = -1;
895	goto done;
896}
897
898
899/* -----------------------------------------------------------------------------
900----------------------------------------------------------------------------- */
901static int process_xauth_need_info(struct service *serv)
902{
903	char *message = NULL;
904	struct vpnctl_cmd_xauth_info *cmd_xauth_info;
905
906	cmd_xauth_info = ALIGNED_CAST(struct vpnctl_cmd_xauth_info *)serv->u.ipsec.msg;
907
908	char *xauth_data = (char*)serv->u.ipsec.msg + sizeof(struct vpnctl_cmd_xauth_info);
909	int xauth_data_len = ntohs(serv->u.ipsec.msghdr.len) - (sizeof(struct vpnctl_cmd_xauth_info) -  sizeof(struct vpnctl_hdr));
910
911	int tlen = xauth_data_len;
912	struct isakmp_data *attr;
913	char	*dataptr = xauth_data;
914
915	serv->u.ipsec.xauth_flags &= ~(XAUTH_NEED_USERNAME | XAUTH_NEED_PASSWORD | XAUTH_NEED_PASSCODE | XAUTH_NEED_ANSWER);
916	serv->u.ipsec.xauth_flags |= XAUTH_NEED_XAUTH_INFO;
917
918	while (tlen > 0)
919	{
920		int tlv;
921		u_int16_t type;
922
923		attr = ALIGNED_CAST(struct isakmp_data *)dataptr;
924		type = ntohs(attr->type) & 0x7FFF;
925		tlv = (type ==  ntohs(attr->type));
926
927		switch (type)
928		{
929			case XAUTH_TYPE:
930				switch (ntohs(attr->lorv)) {
931					case XAUTH_TYPE_GENERIC:
932						break;
933					default:
934						ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Received unsupported Xauth Type (value %d)"), ntohs(attr->lorv));
935						goto fail;
936				}
937				break;
938			case XAUTH_USER_NAME:
939				serv->u.ipsec.xauth_flags |= XAUTH_NEED_USERNAME;
940				serv->u.ipsec.xauth_flags &= ~(XAUTH_NEED_NEXT_PIN + XAUTH_NEED_ANSWER);
941				break;
942			case XAUTH_USER_PASSWORD:
943				serv->u.ipsec.xauth_flags |= XAUTH_NEED_PASSWORD;
944				serv->u.ipsec.xauth_flags &= ~(XAUTH_NEED_PASSCODE + XAUTH_NEED_NEXT_PIN + XAUTH_NEED_ANSWER);
945				break;
946			case XAUTH_PASSCODE:
947				serv->u.ipsec.xauth_flags |= XAUTH_NEED_PASSCODE;
948				serv->u.ipsec.xauth_flags &= ~(XAUTH_NEED_PASSWORD + XAUTH_NEED_NEXT_PIN + XAUTH_NEED_ANSWER);
949				break;
950			case XAUTH_MESSAGE:
951				if (message)	// we've already seen that attribute
952					break;
953				message = malloc(ntohs(attr->lorv) + 1);
954				if (message) {
955					bcopy(dataptr + sizeof(u_int32_t), message, ntohs(attr->lorv));
956					message[ntohs(attr->lorv)] = 0;
957				}
958				break;
959			case XAUTH_CHALLENGE:
960				ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Received unsupported Xauth Challenge"));
961				goto fail;
962				break;
963			case XAUTH_DOMAIN:
964				ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Ignoring unsupported Xauth Domain"));
965				break;
966			case XAUTH_STATUS:
967				ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Received unsupported Xauth Status"));
968				goto fail;
969				break;
970			case XAUTH_NEXT_PIN:
971				serv->u.ipsec.xauth_flags |= XAUTH_NEED_NEXT_PIN;
972				serv->u.ipsec.xauth_flags &= ~(XAUTH_NEED_USERNAME + XAUTH_NEED_PASSWORD + XAUTH_NEED_PASSCODE + XAUTH_NEED_ANSWER);
973				break;
974			case XAUTH_ANSWER:
975				serv->u.ipsec.xauth_flags |= XAUTH_NEED_ANSWER;
976				serv->u.ipsec.xauth_flags &= ~(XAUTH_NEED_USERNAME + XAUTH_NEED_PASSWORD + XAUTH_NEED_PASSCODE + XAUTH_NEED_NEXT_PIN);
977				break;
978			default:
979				break;
980		}
981
982
983		if (tlv) {
984			tlen -= ntohs(attr->lorv);
985			dataptr += ntohs(attr->lorv);
986		}
987
988		tlen -= sizeof(u_int32_t);
989		dataptr += sizeof(u_int32_t);
990
991	}
992
993	if (serv->u.ipsec.xauth_flags & XAUTH_FIRST_TIME || serv->u.ipsec.phase == IPSEC_RUNNING) {
994
995		serv->u.ipsec.xauth_flags &= ~(XAUTH_FIRST_TIME);
996
997		// first time, use credential info from the prefs if they were available
998		// additional times, assume failure and re-prompt
999
1000		if (!(serv->u.ipsec.xauth_flags & XAUTH_MUST_PROMPT)) {
1001
1002			CFStringRef username = NULL;
1003			CFStringRef password = NULL;
1004			int has_info = 0;
1005
1006			if (serv->u.ipsec.xauth_flags & XAUTH_NEED_USERNAME) {
1007				username = CFDictionaryGetValue(serv->u.ipsec.config, kRASPropIPSecXAuthName);
1008				has_info = isString(username) && CFStringGetLength(username);
1009			}
1010
1011			if (has_info || !(serv->u.ipsec.xauth_flags & XAUTH_NEED_USERNAME)) {
1012				if (serv->u.ipsec.xauth_flags & (XAUTH_NEED_PASSWORD | XAUTH_NEED_PASSCODE)) {
1013					if (serv->ne_sm_bridge == NULL) {
1014						password = copy_decrypted_password(serv);
1015					} else {
1016						password = ne_sm_bridge_copy_password_from_keychain(serv->ne_sm_bridge, kSCPropNetIPSecXAuthPassword);
1017					}
1018					has_info = isString(password) && CFStringGetLength(password);
1019				}
1020			}
1021
1022			if (has_info) {
1023
1024				struct isakmp_xauth		isakmp_array[2]; /* max 2 attributes currently supported simultaneously */
1025				int						isakmp_nb = 0;
1026
1027				if (serv->u.ipsec.xauth_flags & XAUTH_NEED_USERNAME) {
1028					isakmp_array[isakmp_nb].type = XAUTH_USER_NAME;
1029					isakmp_array[isakmp_nb].str = username;
1030					isakmp_nb++;
1031				}
1032
1033				if (serv->u.ipsec.xauth_flags & XAUTH_NEED_PASSCODE) {
1034					isakmp_array[isakmp_nb].type = XAUTH_PASSCODE;
1035					isakmp_array[isakmp_nb].str = password;
1036					isakmp_nb++;
1037				}
1038				else if (serv->u.ipsec.xauth_flags & XAUTH_NEED_PASSWORD) {
1039					isakmp_array[isakmp_nb].type = XAUTH_USER_PASSWORD;
1040					isakmp_array[isakmp_nb].str = password;
1041					isakmp_nb++;
1042				}
1043
1044#if TARGET_OS_EMBEDDED
1045				if (serv->u.ipsec.timerref) {
1046					CFRunLoopTimerSetNextFireDate(serv->u.ipsec.timerref, CFAbsoluteTimeGetCurrent() + TIMEOUT_PHASE1);
1047				}
1048				ipsec_updatephase(serv, IPSEC_PHASE1);
1049#else
1050				if (serv->u.ipsec.phase == IPSEC_PHASE1AUTH) {
1051					if (serv->u.ipsec.timerref) {
1052						CFRunLoopTimerSetNextFireDate(serv->u.ipsec.timerref, CFAbsoluteTimeGetCurrent() + TIMEOUT_PHASE1);
1053					}
1054					ipsec_updatephase(serv, IPSEC_PHASE1);
1055				}
1056#endif /* TARGET_OS_EMBEDDED */
1057				racoon_send_cmd_xauthinfo(serv->u.ipsec.controlfd, serv->u.ipsec.peer_address.sin_addr.s_addr, isakmp_array, isakmp_nb);
1058				if (password)
1059					CFRelease(password);
1060				goto done;
1061			}
1062
1063			if (password)
1064				CFRelease(password);
1065		}
1066	}
1067
1068	if (ask_user_xauth(serv, message))
1069		goto fail;
1070
1071	serv->u.ipsec.xauth_flags |= XAUTH_DID_PROMPT;
1072
1073done:
1074	if (message)
1075		free(message);
1076	return 0;
1077
1078fail:
1079	serv->u.ipsec.xauth_flags = 0;
1080	if (message)
1081		free(message);
1082	return 1;
1083}
1084
1085/* -----------------------------------------------------------------------------
1086----------------------------------------------------------------------------- */
1087static void print_racoon_msg(struct service *serv)
1088{
1089	struct vpnctl_status_phase_change *phase_change_status;
1090	struct vpnctl_status_failed *failed_status;
1091	struct vpnctl_cmd_xauth_info *cmd_xauth_info;
1092	struct vpnctl_cmd_bind *cmd_bind;
1093	struct vpnctl_status_peer_resp *peer_resp;
1094	struct in_addr addr;
1095
1096#if 0
1097	char *rawdata = serv->u.ipsec.msg;
1098	int i;
1099
1100	printf("Header = 0x");
1101	for (i= 0; i < sizeof(struct vpnctl_hdr); i++) {
1102		printf("%02X ", rawdata[i]);
1103	}
1104	printf("\nData = 0x");
1105	for (i= 0; i < ntohs(serv->u.ipsec.msghdr.len); i++) {
1106		printf("%02X ", rawdata[i + sizeof(struct vpnctl_hdr)]);
1107	}
1108	printf("\n");
1109#endif
1110
1111	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: ===================================================="));
1112	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: Process Message:"));
1113	ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	msg_type = 0x%x (%s)"), ntohs(serv->u.ipsec.msghdr.msg_type), ipsec_msgtype_to_str(ntohs(serv->u.ipsec.msghdr.msg_type)));
1114	ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	flags = 0x%x %s"), ntohs(serv->u.ipsec.msghdr.flags), (ntohs(serv->u.ipsec.msghdr.flags) & VPNCTL_FLAG_MODECFG_USED) ? "MODE CONFIG USED" : "");
1115	ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	cookie = 0x%x"), ntohl(serv->u.ipsec.msghdr.cookie));
1116	ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	reserved = 0x%x"), ntohl(serv->u.ipsec.msghdr.reserved));
1117	ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	result = 0x%x"), ntohs(serv->u.ipsec.msghdr.result));
1118	ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	len = %d"), ntohs(serv->u.ipsec.msghdr.len));
1119
1120
1121	switch (ntohs(serv->u.ipsec.msghdr.msg_type)) {
1122			// BIND/UNBIND/CONNECT share the same structure
1123			case VPNCTL_CMD_BIND:
1124			case VPNCTL_CMD_UNBIND:
1125			case VPNCTL_CMD_CONNECT:
1126			case VPNCTL_CMD_RECONNECT:
1127			case VPNCTL_CMD_DISCONNECT:
1128				cmd_bind = ALIGNED_CAST(struct vpnctl_cmd_bind *)serv->u.ipsec.msg;
1129				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	----------------------------"));
1130				addr.s_addr = cmd_bind->address;
1131				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	address = %s"), inet_ntoa(addr));
1132				break;
1133
1134			case VPNCTL_CMD_XAUTH_INFO:
1135				cmd_xauth_info = ALIGNED_CAST(struct vpnctl_cmd_xauth_info *)serv->u.ipsec.msg;
1136				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	----------------------------"));
1137				addr.s_addr = cmd_xauth_info->address;
1138				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	address = %s"), inet_ntoa(addr));
1139				break;
1140
1141			case VPNCTL_STATUS_IKE_FAILED:
1142				failed_status = ALIGNED_CAST(struct vpnctl_status_failed *)serv->u.ipsec.msg;
1143				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	----------------------------"));
1144				addr.s_addr = failed_status->address;
1145				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	address = %s"), inet_ntoa(addr));
1146				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	ike_code = %d 0x%x (%s)"), ntohs(failed_status->ike_code), ntohs(failed_status->ike_code), ipsec_error_to_str(ntohs(failed_status->ike_code)));
1147				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	from = %d"), ntohs(failed_status->from));
1148
1149				switch (ntohs(failed_status->ike_code)) {
1150					case VPNCTL_NTYPE_LOAD_BALANCE:
1151						addr.s_addr = *ALIGNED_CAST(u_int32_t*)failed_status->data;
1152						ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	redirect address = %s"), inet_ntoa(addr));
1153						break;
1154				}
1155
1156				break;
1157
1158			case VPNCTL_STATUS_PH1_START_US:
1159				break;
1160
1161			case VPNCTL_STATUS_PH1_START_PEER:
1162				break;
1163
1164			case VPNCTL_STATUS_PH1_ESTABLISHED:
1165				phase_change_status = ALIGNED_CAST(struct vpnctl_status_phase_change *)serv->u.ipsec.msg;
1166				addr.s_addr = phase_change_status->address;
1167				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	address = %s"), inet_ntoa(addr));
1168				if (ntohs(phase_change_status->hdr.flags) & VPNCTL_FLAG_MODECFG_USED) {
1169					char *modecfg_data = (char*)serv->u.ipsec.msg + sizeof(struct vpnctl_status_phase_change) + sizeof(struct vpnctl_modecfg_params);
1170					int modecfg_data_len = ntohs(serv->u.ipsec.msghdr.len) - ((sizeof(struct vpnctl_status_phase_change) + sizeof(struct vpnctl_modecfg_params)) -  sizeof(struct vpnctl_hdr));
1171					struct vpnctl_modecfg_params *modecfg = ALIGNED_CAST(struct vpnctl_modecfg_params *)(void*)(serv->u.ipsec.msg + sizeof(struct vpnctl_status_phase_change));
1172					addr.s_addr = modecfg->outer_local_addr;
1173					ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	outer_local_addr = %s"), inet_ntoa(addr));
1174					ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	outer_remote_port = %d"), ntohs(modecfg->outer_remote_port));
1175					ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	outer_local_port = %d"), ntohs(modecfg->outer_local_port));
1176					ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	ifname = %s"), modecfg->ifname);
1177
1178					int tlen = modecfg_data_len;
1179					char	*dataptr = modecfg_data;
1180
1181					while (tlen > 0)
1182					{
1183						int tlv;
1184						u_int16_t type;
1185                        struct isakmp_data attr;
1186
1187                        memcpy(&attr, dataptr, sizeof(attr));       // Wcast-align fix - memcpy for unaligned access
1188						type = ntohs(attr.type) & 0x7FFF;
1189						tlv = (type ==  ntohs(attr.type));
1190
1191						ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	ModeConfig Attribute Type = %d (%s)"), type, ipsec_modecfgtype_to_str(type));
1192						if (tlv) {
1193							ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	ModeConfig Attribute Length = %d Value = ..."), ntohs(attr.lorv));
1194
1195							tlen -= ntohs(attr.lorv);
1196							dataptr += ntohs(attr.lorv);
1197						}
1198						else {
1199							ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	ModeConfig Attribute Value = %d"), ntohs(attr.lorv));
1200						}
1201
1202						tlen -= sizeof(u_int32_t);
1203						dataptr += sizeof(u_int32_t);
1204
1205					}
1206				}
1207				break;
1208
1209			case VPNCTL_STATUS_PH2_START:
1210				break;
1211
1212			case VPNCTL_STATUS_PH2_ESTABLISHED:
1213				break;
1214
1215			case VPNCTL_STATUS_NEED_AUTHINFO:
1216#if !TARGET_OS_EMBEDDED
1217			case VPNCTL_STATUS_NEED_REAUTHINFO:
1218#endif /* !TARGET_OS_EMBEDDED */
1219				cmd_xauth_info = ALIGNED_CAST(struct vpnctl_cmd_xauth_info *)serv->u.ipsec.msg;
1220				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	----------------------------"));
1221				addr.s_addr = cmd_xauth_info->address;
1222				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	address = %s"), inet_ntoa(addr));
1223
1224				char *xauth_data = (char*)serv->u.ipsec.msg + sizeof(struct vpnctl_cmd_xauth_info);
1225				int xauth_data_len = ntohs(serv->u.ipsec.msghdr.len) - (sizeof(struct vpnctl_cmd_xauth_info) -  sizeof(struct vpnctl_hdr));
1226
1227				int tlen = xauth_data_len;
1228				char	*dataptr = xauth_data;
1229
1230				while (tlen > 0)
1231				{
1232					int tlv;
1233					u_int16_t type;
1234					struct isakmp_data attr;
1235
1236                    memcpy(&attr, dataptr, sizeof(attr));   // Wcast-align fix - memcpy for unaligned access
1237					type = ntohs(attr.type) & 0x7FFF;
1238					tlv = (type ==  ntohs(attr.type));
1239
1240					ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	XAuth Attribute Type = %d (%s)"), type, ipsec_xauthtype_to_str(type));
1241					if (tlv) {
1242						if (type == XAUTH_MESSAGE) {
1243							char *message = malloc(ntohs(attr.lorv) + 1);
1244							if (message) {
1245								bcopy(dataptr + sizeof(u_int32_t), message, ntohs(attr.lorv));
1246								message[ntohs(attr.lorv)] = 0;
1247								ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	XAuth Attribute Value = %s"), message);
1248								free(message);
1249							}
1250						}
1251						else
1252							ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	XAuth Attribute Length = %d Value = ..."), ntohs(attr.lorv));
1253
1254						tlen -= ntohs(attr.lorv);
1255						dataptr += ntohs(attr.lorv);
1256					}
1257					else {
1258						ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	XAuth Attribute Value = %d"), ntohs(attr.lorv));
1259					}
1260
1261					tlen -= sizeof(u_int32_t);
1262					dataptr += sizeof(u_int32_t);
1263
1264				}
1265				break;
1266
1267			case VPNCTL_STATUS_PEER_RESP:
1268				peer_resp = ALIGNED_CAST(__typeof__(peer_resp))serv->u.ipsec.msg;
1269				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	----------------------------"));
1270				addr.s_addr = peer_resp->address;
1271				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	response from address = %s"), inet_ntoa(addr));
1272				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	ike_code = %d"), ntohs(peer_resp->ike_code));
1273				break;
1274
1275			default:
1276				/* ignore other messages */
1277				break;
1278	}
1279
1280	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: ===================================================="));
1281
1282}
1283
1284/* -----------------------------------------------------------------------------
1285----------------------------------------------------------------------------- */
1286static void process_racoon_msg(struct service *serv)
1287{
1288	struct vpnctl_status_phase_change *phase_change_status;
1289	struct vpnctl_status_failed *failed_status;
1290	struct vpnctl_status_peer_resp *peer_resp;
1291	struct sockaddr_in	redirect_addr;
1292	struct in_addr peer_addr;
1293
1294
1295	if (gSCNCVerbose)
1296		print_racoon_msg(serv);
1297
1298	switch (ntohs(serv->u.ipsec.msghdr.msg_type)) {
1299			case VPNCTL_STATUS_IKE_FAILED:
1300				ipsec_log(LOG_ERR, CFSTR("IPSec Controller: IKE FAILED. phase %d, assert %d"), serv->u.ipsec.phase, serv->u.ipsec.asserted);
1301				failed_status = ALIGNED_CAST(struct vpnctl_status_failed *)serv->u.ipsec.msg;
1302
1303				switch (ntohs(failed_status->ike_code)) {
1304
1305					case VPNCTL_NTYPE_LOAD_BALANCE:
1306						bzero(&redirect_addr, sizeof(redirect_addr));
1307						redirect_addr.sin_len = sizeof(redirect_addr);
1308						redirect_addr.sin_family = AF_INET;
1309						redirect_addr.sin_port = htons(0);
1310						redirect_addr.sin_addr.s_addr = *ALIGNED_CAST(u_int32_t*)failed_status->data;
1311						ipsec_log(LOG_INFO, CFSTR("IPSec Controller: connection redirected to server '%s'..."), inet_ntoa(redirect_addr.sin_addr));
1312						racoon_restart(serv, &redirect_addr);
1313						break;
1314
1315					default:
1316						ipsec_log(LOG_INFO, CFSTR("IPSec Controller: connection failed <IKE Error %d (0x%x) %s>"), ntohs(failed_status->ike_code), ntohs(failed_status->ike_code), ipsec_error_to_str(ntohs(failed_status->ike_code)));
1317						serv->u.ipsec.laststatus = ipsec_error_to_status(serv, ntohs(failed_status->from), ntohs(failed_status->ike_code));
1318
1319						/* after phase 2, an authenticaion error is because the peer is disconnecting us */
1320						if ((serv->u.ipsec.laststatus == IPSEC_XAUTH_ERROR) && (serv->u.ipsec.phase >= IPSEC_PHASE2))
1321							serv->u.ipsec.laststatus = IPSEC_PEERDISCONNECT_ERROR;
1322						ipsec_stop(serv, 0);
1323						break;
1324				}
1325
1326				break;
1327
1328			case VPNCTL_STATUS_PH1_START_US:
1329				ipsec_log(LOG_INFO, CFSTR("IPSec Controller: PH1 STARTUS. phase %d, assert %d"), serv->u.ipsec.phase, serv->u.ipsec.asserted);
1330				if (serv->u.ipsec.phase == IPSEC_INITIALIZE) {
1331					ipsec_updatephase(serv, IPSEC_CONTACT);
1332				} else if (IPSEC_IS_ASSERTED_IDLE(serv->u.ipsec) ||
1333						   IPSEC_IS_ASSERTED_INITIALIZE(serv->u.ipsec)) {
1334					if (IPSEC_IS_ASSERTED_IDLE(serv->u.ipsec) && serv->u.ipsec.timerref) {
1335						CFRunLoopTimerSetNextFireDate(serv->u.ipsec.timerref, CFAbsoluteTimeGetCurrent() + TIMEOUT_INITIAL_CONTACT);
1336					}
1337					IPSEC_ASSERT_CONTACT(serv->u.ipsec);
1338				}
1339				break;
1340
1341			case VPNCTL_STATUS_PH1_START_PEER:
1342				ipsec_log(LOG_INFO, CFSTR("IPSec Controller: PH1 STARTPEER. phase %d, assert %d"), serv->u.ipsec.phase, serv->u.ipsec.asserted);
1343				if (serv->u.ipsec.phase != IPSEC_CONTACT && !IPSEC_IS_ASSERTED_CONTACT(serv->u.ipsec))
1344					break;
1345				if (serv->u.ipsec.timerref) {
1346					CFRunLoopTimerSetNextFireDate(serv->u.ipsec.timerref, CFAbsoluteTimeGetCurrent() + TIMEOUT_PHASE1);
1347				}
1348				if (serv->u.ipsec.phase == IPSEC_CONTACT) {
1349					ipsec_updatephase(serv, IPSEC_PHASE1);
1350				} else if (IPSEC_IS_ASSERTED_CONTACT(serv->u.ipsec)) {
1351					IPSEC_ASSERT_PHASE1(serv->u.ipsec);
1352				}
1353				break;
1354
1355			case VPNCTL_STATUS_NEED_AUTHINFO:
1356				ipsec_log(LOG_INFO, CFSTR("IPSec Controller: AUTHINFO. phase %d, assert %d"), serv->u.ipsec.phase, serv->u.ipsec.asserted);
1357				if (serv->u.ipsec.phase != IPSEC_PHASE1 && !IPSEC_IS_ASSERTED_PHASE1(serv->u.ipsec))
1358					break;
1359				if (serv->u.ipsec.phase == IPSEC_PHASE1) {
1360					ipsec_updatephase(serv, IPSEC_PHASE1AUTH);
1361				} else if (IPSEC_IS_ASSERTED_PHASE1(serv->u.ipsec)) {
1362					// disconnect if we have to prompt user
1363					if (serv->u.ipsec.xauth_flags & XAUTH_MUST_PROMPT) {
1364						ipsec_log(LOG_ERR, CFSTR("IPSec Controller: session asserting but XAuth dialog required, so connection aborted"));
1365						ipsec_stop(serv, 0);
1366						break;
1367					}
1368				}
1369				if (serv->u.ipsec.timerref) {
1370					CFRunLoopTimerSetNextFireDate(serv->u.ipsec.timerref, FAR_FUTURE);
1371				}
1372				IPSECLOGASLMSG("IPSec requesting Extended Authentication.\n");
1373
1374				if (process_xauth_need_info(serv)) {
1375					ipsec_log(LOG_ERR, CFSTR("IPSec Controller: XAuth authentication failed"));
1376					ipsec_stop(serv, 0);
1377				}
1378				break;
1379
1380			case VPNCTL_STATUS_PH1_ESTABLISHED:
1381				ipsec_log(LOG_INFO, CFSTR("IPSec Controller: PH1 ESTABLISHED. phase %d, assert %d"), serv->u.ipsec.phase, serv->u.ipsec.asserted);
1382				if (serv->u.ipsec.phase != IPSEC_PHASE1 && !IPSEC_IS_ASSERTED_PHASE1(serv->u.ipsec))
1383					break;
1384				if (serv->u.ipsec.phase == IPSEC_PHASE1) {
1385					phase_change_status = ALIGNED_CAST(struct vpnctl_status_phase_change *)serv->u.ipsec.msg;
1386					bool requestedInstall = false;
1387					if (serv->ne_sm_bridge != NULL) {
1388						if (serv->u.ipsec.modecfg_msg != NULL) {
1389							my_Deallocate(serv->u.ipsec.modecfg_msg, serv->u.ipsec.modecfg_msglen);
1390							serv->u.ipsec.modecfg_msg = NULL;
1391						}
1392						serv->u.ipsec.modecfg_msglen = serv->u.ipsec.msgtotallen + 1;
1393						serv->u.ipsec.modecfg_msg = my_Allocate(serv->u.ipsec.modecfg_msglen);
1394						memcpy(serv->u.ipsec.modecfg_msg, serv->u.ipsec.msg, serv->u.ipsec.modecfg_msglen);
1395						requestedInstall = ne_sm_bridge_request_install(serv->ne_sm_bridge, mode_config_is_default(serv));
1396						install_mode_config(serv, FALSE, TRUE);
1397					}
1398					if (!requestedInstall) {
1399						if (ntohs(phase_change_status->hdr.flags) & VPNCTL_FLAG_MODECFG_USED) {
1400							install_mode_config(serv, TRUE, TRUE);
1401						}
1402					}
1403					serv->u.ipsec.ping_count = MAX_PHASE2_PING;
1404					if (serv->u.ipsec.timerref) {
1405						CFRunLoopTimerSetNextFireDate(serv->u.ipsec.timerref, CFAbsoluteTimeGetCurrent() + TIMEOUT_PHASE2_PING);
1406					}
1407					serv->connecttime = mach_absolute_time() * gTimeScaleSeconds;
1408					serv->connectionslepttime = 0;
1409				} else if (IPSEC_IS_ASSERTED_PHASE1(serv->u.ipsec)) {
1410					if (unassert_mode_config(serv)) {
1411						ipsec_log(LOG_ERR, CFSTR("IPSec Controller: unassert failed"));
1412						ipsec_stop(serv, 0);
1413						break;
1414					}
1415				}
1416				IPSECLOGASLMSG("IPSec Phase1 established.\n");
1417				break;
1418
1419			case VPNCTL_STATUS_PH2_START:
1420				ipsec_log(LOG_INFO, CFSTR("IPSec Controller: PH2 START. phase %d, assert %d"), serv->u.ipsec.phase, serv->u.ipsec.asserted);
1421				if (serv->u.ipsec.phase != IPSEC_PHASE1 && !IPSEC_IS_ASSERTED_PHASE1(serv->u.ipsec))
1422					break;
1423				if (serv->u.ipsec.phase == IPSEC_PHASE1) {
1424					if (serv->u.ipsec.timerref) {
1425						CFRunLoopTimerSetNextFireDate(serv->u.ipsec.timerref, CFAbsoluteTimeGetCurrent() + TIMEOUT_PHASE2);
1426					}
1427					ipsec_updatephase(serv, IPSEC_PHASE2);
1428				} else if (IPSEC_IS_ASSERTED_PHASE1(serv->u.ipsec)) {
1429					IPSEC_ASSERT_PHASE2(serv->u.ipsec);
1430				}
1431				break;
1432
1433			case VPNCTL_STATUS_PH2_ESTABLISHED:
1434				ipsec_log(LOG_INFO, CFSTR("IPSec Controller: PH2 ESTABLISHED. phase %d, assert %d"), serv->u.ipsec.phase, serv->u.ipsec.asserted);
1435				if (serv->u.ipsec.phase != IPSEC_PHASE2 && !IPSEC_IS_ASSERTED_PHASE2(serv->u.ipsec))
1436					break;
1437				if (serv->u.ipsec.timerref) {
1438					CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), serv->u.ipsec.timerref, kCFRunLoopCommonModes);
1439				}
1440				my_CFRelease(&serv->u.ipsec.timerref);
1441				if (serv->u.ipsec.phase == IPSEC_PHASE2) {
1442					if (serv->u.ipsec.banner && !(serv->flags & FLAG_ONDEMAND)) {
1443						display_notification(serv, serv->u.ipsec.banner, 0, dialog_has_disconnect_type);
1444						my_CFRelease(&serv->u.ipsec.banner);
1445					}
1446					SESSIONTRACERESTABLISHED(serv);
1447				} else if (IPSEC_IS_ASSERTED_PHASE2(serv->u.ipsec)) {
1448					IPSEC_UNASSERT(serv->u.ipsec);
1449				}
1450				ipsec_updatephase(serv, IPSEC_RUNNING);
1451				serv->was_running = 1;
1452				IPSECLOGASLMSG("IPSec Phase2 established.\n");
1453				break;
1454
1455#if !TARGET_OS_EMBEDDED
1456			case VPNCTL_STATUS_NEED_REAUTHINFO:
1457				ipsec_log(LOG_INFO, CFSTR("IPSec Controller: REAUTHINFO. phase %d, assert %d"), serv->u.ipsec.phase, serv->u.ipsec.asserted);
1458				if (serv->u.ipsec.phase != IPSEC_RUNNING && !IPSEC_IS_ASSERTED_PHASE1(serv->u.ipsec))
1459					break;
1460
1461				IPSECLOGASLMSG("IPSec requesting Extended Authentication.\n");
1462
1463				// disconnect if we have to prompt user
1464				if (serv->u.ipsec.xauth_flags & XAUTH_MUST_PROMPT) {
1465					ipsec_log(LOG_ERR, CFSTR("IPSec Controller: XAuth reauthentication dialog required, so connection aborted"));
1466					ipsec_stop(serv, 0);
1467				} else if (process_xauth_need_info(serv)) {
1468					ipsec_log(LOG_ERR, CFSTR("IPSec Controller: XAuth reauthentication failed"));
1469					ipsec_stop(serv, 0);
1470				}
1471				break;
1472#endif /* !TARGET_OS_EMBEDDED */
1473
1474			case VPNCTL_STATUS_PEER_RESP:
1475				ipsec_log(LOG_INFO, CFSTR("IPSec Controller: PEER RESP. phase %d, assert %d"), serv->u.ipsec.phase, serv->u.ipsec.asserted);
1476				peer_resp = ALIGNED_CAST(__typeof__(peer_resp))serv->u.ipsec.msg;
1477				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	----------------------------"));
1478				peer_addr.s_addr = peer_resp->address;
1479				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	response from address = %s"), inet_ntoa(peer_addr));
1480				ipsec_log(LOG_INFO, CFSTR("IPSec Controller:	ike_code = %d"), ntohs(peer_resp->ike_code));
1481				if (!serv->u.ipsec.awaiting_peer_resp) {
1482					ipsec_log(LOG_ERR, CFSTR("IPSec Controller: unsolicited peer response notification"));
1483				}
1484				serv->u.ipsec.awaiting_peer_resp = 0;
1485				break;
1486
1487			default:
1488				/* ignore other messages */
1489				break;
1490	}
1491}
1492
1493int ipsec_install(struct service *serv)
1494{
1495	install_mode_config(serv, TRUE, FALSE);
1496	return 0;
1497}
1498
1499int ipsec_uninstall(struct service *serv)
1500{
1501	uninstall_mode_config(serv, FALSE);
1502	return 0;
1503}
1504
1505
1506/* ----------------------------------------------------------------------------
1507 ----------------------------------------------------------------------------- */
1508int ipsec_ondemand_add_service_data(struct service *serv, CFMutableDictionaryRef ondemand_dict)
1509{
1510	CFArrayRef			array;
1511	CFStringRef			string;
1512
1513	array = CFDictionaryGetValue(serv->systemprefs, kSCPropNetIPSecOnDemandMatchDomainsAlways);
1514	if (isArray(array))
1515		CFDictionarySetValue(ondemand_dict, kSCNetworkConnectionOnDemandMatchDomainsAlways, array);
1516	array = CFDictionaryGetValue(serv->systemprefs, kSCPropNetIPSecOnDemandMatchDomainsOnRetry);
1517	if (isArray(array))
1518		CFDictionarySetValue(ondemand_dict, kSCNetworkConnectionOnDemandMatchDomainsOnRetry, array);
1519	array = CFDictionaryGetValue(serv->systemprefs, kSCPropNetIPSecOnDemandMatchDomainsNever);
1520	if (isArray(array))
1521		CFDictionarySetValue(ondemand_dict, kSCNetworkConnectionOnDemandMatchDomainsNever, array);
1522
1523	string = CFDictionaryGetValue(serv->systemprefs, kRASPropIPSecRemoteAddress);
1524	if (isString(string))
1525		CFDictionarySetValue(ondemand_dict, kSCNetworkConnectionOnDemandRemoteAddress, string);
1526
1527	return 0;
1528}
1529/* -----------------------------------------------------------------------------
1530----------------------------------------------------------------------------- */
1531static int
1532racoon_trigger_phase2(char *ifname, struct in_addr *ping)
1533{
1534	struct icmp *icp;
1535	int cc, i, j, nbping;
1536	struct sockaddr_in whereto;	/* who to ping */
1537	uint8_t data[256] __attribute__ ((aligned (4)));
1538	int s, ifindex;
1539
1540	s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
1541	if (s < 0)
1542		return -1;
1543
1544	ifindex = if_nametoindex(ifname);
1545	setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex));
1546
1547	whereto.sin_family = AF_INET;	/* Internet address family */
1548	whereto.sin_port = 0;		/* Source port */
1549	whereto.sin_addr.s_addr = ping->s_addr;	/* Dest. address */
1550
1551	icp = ALIGNED_CAST(struct icmp *)data;
1552	icp->icmp_type = ICMP_ECHO;
1553	icp->icmp_code = 0;
1554	icp->icmp_cksum = 0;
1555	icp->icmp_seq = htons(0);
1556	icp->icmp_id = 0;			/* ID */
1557
1558	cc = ICMP_MINLEN;
1559
1560	size_t len = sizeof(int);
1561	if (sysctlbyname("net.key.blockacq_count", &nbping, &len, 0, 0))
1562		nbping = 10;
1563
1564	for (j = 0; j <= nbping; j++) {
1565		i = sendto(s, data, cc, 0, (struct sockaddr *)&whereto, sizeof(whereto));
1566		if (i < cc) {
1567			close(s);
1568			return -1;
1569		}
1570	}
1571	close(s);
1572	return 0;
1573}
1574
1575static Boolean add_ipv4_route (CFMutableArrayRef routesArray, uint32_t address, uint32_t netmask, uint32_t gateway, Boolean isExcludedRoute, char * delegateInterfaceName)
1576{
1577	CFStringRef string = NULL;
1578	struct in_addr addr;
1579
1580	if (!isA_CFArray(routesArray))
1581	{
1582		return FALSE;
1583	}
1584
1585	CFMutableDictionaryRef newRouteDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1586	if (!isA_CFDictionary(newRouteDictionary))
1587	{
1588		return FALSE;
1589	}
1590
1591	addr.s_addr = address;
1592	if ((string = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) {
1593		CFDictionarySetValue(newRouteDictionary, kSCPropNetIPv4RouteDestinationAddress, string);
1594		my_CFRelease(&string);
1595	}
1596
1597	if (netmask) {
1598		addr.s_addr = netmask;
1599		if ((string = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) {
1600			CFDictionarySetValue(newRouteDictionary, kSCPropNetIPv4RouteSubnetMask, string);
1601			my_CFRelease(&string);
1602		}
1603	}
1604
1605	if (gateway) {
1606		addr.s_addr = gateway;
1607		if ((string = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) {
1608			CFDictionarySetValue(newRouteDictionary, kSCPropNetIPv4RouteGatewayAddress, string);
1609			my_CFRelease(&string);
1610		}
1611	}
1612
1613	if (isExcludedRoute && delegateInterfaceName) {
1614		if ((string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), delegateInterfaceName))) {
1615			CFDictionarySetValue(newRouteDictionary, kSCPropNetIPv4RouteInterfaceName, string);
1616			CFRelease(string);
1617		}
1618	}
1619
1620	CFArrayAppendValue(routesArray, newRouteDictionary);
1621	my_CFRelease(&newRouteDictionary);
1622
1623	return TRUE;
1624}
1625
1626
1627static CFArrayRef create_ipv4_route_array(struct service *serv, CFDictionaryRef ipsec_dict, struct in_addr gateway)
1628{
1629	CFMutableArrayRef routesArray = NULL;
1630	int	i, nb;
1631	CFArrayRef policies = NULL;
1632	struct sockaddr_in remote_net;
1633	char str[32];
1634	u_int32_t remote_prefix;
1635
1636	routesArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1637
1638	policies = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecPolicies);
1639	if (!isA_CFArray(policies) || (nb = CFArrayGetCount(policies)) == 0) {
1640		goto done;
1641	}
1642
1643	for (i = 0; i < nb; i++) {
1644		CFDictionaryRef policy;
1645		CFStringRef policymode, policydirection, policylevel;
1646
1647		policy = CFArrayGetValueAtIndex(policies, i);
1648		if (!isDictionary(policy)) {
1649			continue;
1650		}
1651
1652		/* build policies in and out */
1653
1654		policymode = CFDictionaryGetValue(policy, kRASPropIPSecPolicyMode);
1655		if (!isA_CFString(policymode) || !CFEqual(policymode, kRASValIPSecPolicyModeTunnel)) {
1656			continue;
1657		}
1658
1659		/* if policy direction is not specified, in/out is assumed */
1660		policydirection = CFDictionaryGetValue(policy, kRASPropIPSecPolicyDirection);
1661		if (!isA_CFString(policydirection) || (!CFEqual(policydirection, kRASValIPSecPolicyDirectionOut) && !CFEqual(policydirection, kRASValIPSecPolicyDirectionInOut))) {
1662			continue;
1663		}
1664
1665		policylevel = CFDictionaryGetValue(policy, kRASPropIPSecPolicyLevel);
1666		if (!isA_CFString(policylevel) || CFEqual(policylevel, kRASValIPSecPolicyLevelNone)) {
1667			continue; // no need for routes for 'none' policies
1668		}
1669
1670		if (!CFEqual(policylevel, kRASValIPSecPolicyLevelRequire) && !CFEqual(policylevel, kRASValIPSecPolicyLevelDiscard)  && !CFEqual(policylevel, kRASValIPSecPolicyLevelUnique)) {
1671			continue;
1672		}
1673
1674		/* get remote network */
1675		if (!GetStrNetFromDict(policy, kRASPropIPSecPolicyRemoteAddress, str, sizeof(str))) {
1676			continue;
1677		}
1678		remote_net.sin_len = sizeof(remote_net);
1679		remote_net.sin_family = AF_INET;
1680		remote_net.sin_port = htons(0);
1681		if (!inet_aton(str, &remote_net.sin_addr)) {
1682			continue;
1683		}
1684
1685		uint32_t mask = 0;
1686		GetIntFromDict(policy, kRASPropIPSecPolicyRemotePrefix, &remote_prefix, 24);
1687		for (mask = 0; remote_prefix; remote_prefix--) {
1688			mask = (mask >> 1) | 0x80000000;
1689		}
1690		mask = htonl(mask);
1691
1692		add_ipv4_route(routesArray, remote_net.sin_addr.s_addr, mask, gateway.s_addr, FALSE, NULL);
1693	}
1694
1695done:
1696	return routesArray;
1697}
1698
1699/* -----------------------------------------------------------------------------
1700----------------------------------------------------------------------------- */
1701static void uninstall_mode_config(struct service *serv, Boolean uninstallPolicies)
1702{
1703    CFMutableArrayRef dicts_to_remove;
1704	int		error = 0;
1705	char	*errorstr;
1706
1707	if (serv->u.ipsec.modecfg_installed) {
1708		dicts_to_remove = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1709		CFArrayAppendValue(dicts_to_remove, kSCEntNetIPv4);
1710		if (serv->u.ipsec.dummy_ipv6_installed) {
1711			CFArrayAppendValue(dicts_to_remove, kSCEntNetIPv6);
1712			serv->u.ipsec.dummy_ipv6_installed = 0;
1713		}
1714		CFArrayAppendValue(dicts_to_remove, kSCEntNetDNS);
1715		/* Unpublish all-at-once */
1716		unpublish_multiple_dicts(gDynamicStore, serv->serviceID, dicts_to_remove, TRUE);
1717		my_CFRelease(&dicts_to_remove);
1718
1719		if (serv->u.ipsec.modecfg_defaultroute) {
1720			// don't need that since we unplished the whole dictionary
1721			// unpublish_dictentry(gDynamicStore, serv->serviceID, kSCEntNetIPv4, kSCPropNetOverridePrimary);
1722			serv->u.ipsec.modecfg_defaultroute = 0;
1723		}
1724
1725		my_CFRelease(&serv->u.ipsec.banner);
1726
1727		serv->u.ipsec.modecfg_installed = 0;
1728	}
1729	if (serv->u.ipsec.modecfg_policies_installed && uninstallPolicies) {
1730		if (serv->u.ipsec.modecfg_policies) {
1731			error = IPSecRemovePolicies(serv->u.ipsec.modecfg_policies, -1,  &errorstr);
1732			if (error)
1733			ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Cannot remove mode config policies, error '%s'"), errorstr);
1734			my_CFRelease(&serv->u.ipsec.modecfg_policies);
1735		}
1736
1737		IPSecRemoveSecurityAssociations((struct sockaddr *)&serv->u.ipsec.our_address, (struct sockaddr *)&serv->u.ipsec.peer_address);
1738
1739		clear_ifaddr(serv->if_name, serv->u.ipsec.inner_local_addr, 0xFFFFFFFF);
1740		my_close(serv->u.ipsec.kernctl_sock);
1741		serv->u.ipsec.kernctl_sock = -1;
1742
1743		free_service_routes(serv);
1744		serv->u.ipsec.modecfg_policies_installed = 0;
1745	}
1746}
1747
1748static void format_routes_for_cache (struct service *serv, struct in_addr *included_address_gateway, int isdefault)
1749{
1750	CFMutableDataRef	includedRouteAddressData = CFDataCreateMutable(kCFAllocatorDefault, 0);
1751	CFMutableDataRef	includedRouteMaskData = CFDataCreateMutable(kCFAllocatorDefault, 0);
1752	CFMutableDataRef	excludedRouteAddressData = CFDataCreateMutable(kCFAllocatorDefault, 0);
1753	CFMutableDataRef	excludedRouteMaskData = CFDataCreateMutable(kCFAllocatorDefault, 0);
1754	service_route_t *route = NULL;
1755
1756	if (includedRouteAddressData == NULL ||
1757		includedRouteMaskData == NULL ||
1758		excludedRouteAddressData == NULL ||
1759		excludedRouteMaskData == NULL) {
1760		goto done;
1761	}
1762
1763	for (route = serv->u.ipsec.routes; route != NULL; route = route->next) {
1764		if (route->gtwy_address.s_addr == included_address_gateway->s_addr) {
1765			CFDataAppendBytes(includedRouteAddressData, (uint8_t*)&route->dest_address, sizeof(struct in_addr));
1766			CFDataAppendBytes(includedRouteMaskData, (uint8_t*)&route->dest_mask, sizeof(struct in_addr));
1767		} else {
1768			CFDataAppendBytes(excludedRouteAddressData, (uint8_t*)&route->dest_address, sizeof(struct in_addr));
1769			CFDataAppendBytes(excludedRouteMaskData, (uint8_t*)&route->dest_mask, sizeof(struct in_addr));
1770		}
1771	}
1772
1773	/* Send info to cache */
1774	CFMutableDictionaryRef routesDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1775	if (routesDict) {
1776		CFMutableDictionaryRef ipv4RoutesDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1777		if (ipv4RoutesDict) {
1778			if (CFDataGetLength(includedRouteAddressData)) {
1779				CFMutableDictionaryRef includedRoutesDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1780				if (includedRoutesDict) {
1781					CFDictionaryAddValue(includedRoutesDict, kSCNetworkConnectionNetworkInfoAddresses, includedRouteAddressData);
1782					CFDictionaryAddValue(includedRoutesDict, kSCNetworkConnectionNetworkInfoMasks, includedRouteMaskData);
1783					CFDictionaryAddValue(ipv4RoutesDict, kSCNetworkConnectionNetworkInfoIncludedRoutes, includedRoutesDict);
1784					CFRelease(includedRoutesDict);
1785				}
1786			}
1787
1788			if (CFDataGetLength(excludedRouteAddressData)) {
1789				CFMutableDictionaryRef excludedRoutesDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1790				if (excludedRoutesDict) {
1791					CFDictionaryAddValue(excludedRoutesDict, kSCNetworkConnectionNetworkInfoAddresses, excludedRouteAddressData);
1792					CFDictionaryAddValue(excludedRoutesDict, kSCNetworkConnectionNetworkInfoMasks, excludedRouteMaskData);
1793					CFDictionaryAddValue(ipv4RoutesDict, kSCNetworkConnectionNetworkInfoExcludedRoutes, excludedRoutesDict);
1794					CFRelease(excludedRoutesDict);
1795				}
1796			}
1797
1798			CFDictionaryAddValue(routesDict, kSCNetworkConnectionNetworkInfoIPv4, ipv4RoutesDict);
1799			CFRelease(ipv4RoutesDict);
1800		}
1801		scnc_cache_routing_table(serv, routesDict, FALSE, (isdefault != 0));
1802		CFRelease(routesDict);
1803	}
1804
1805done:
1806	my_CFRelease(&includedRouteAddressData);
1807	my_CFRelease(&includedRouteMaskData);
1808	my_CFRelease(&excludedRouteAddressData);
1809	my_CFRelease(&excludedRouteMaskData);
1810}
1811
1812static bool mode_config_is_default(struct service *serv)
1813{
1814	bool isdefault = true;
1815	struct isakmp_data attr;
1816	char *modecfg_data = (char*)serv->u.ipsec.msg + sizeof(struct vpnctl_status_phase_change) + sizeof(struct vpnctl_modecfg_params);
1817	int modecfg_data_len = ntohs(serv->u.ipsec.msghdr.len) - ((sizeof(struct vpnctl_status_phase_change) + sizeof(struct vpnctl_modecfg_params)) -  sizeof(struct vpnctl_hdr));
1818	int tlen = modecfg_data_len;
1819	char *dataptr = modecfg_data;
1820
1821	while (tlen > 0)
1822	{
1823		int tlv;
1824		u_int16_t type;
1825
1826		memcpy(&attr, dataptr, sizeof(attr));        // Wcast-align fix - memcpy for unaligned access
1827		type = ntohs(attr.type) & 0x7FFF;
1828		tlv = (type ==  ntohs(attr.type));
1829
1830
1831		if (type == UNITY_SPLIT_INCLUDE) {
1832			isdefault = false;
1833			break;
1834		}
1835
1836		if (tlv) {
1837			tlen -= ntohs(attr.lorv);
1838			dataptr += ntohs(attr.lorv);
1839		}
1840
1841		tlen -= sizeof(u_int32_t);
1842		dataptr += sizeof(u_int32_t);
1843	}
1844
1845	return isdefault;
1846}
1847
1848/* -----------------------------------------------------------------------------
1849----------------------------------------------------------------------------- */
1850static void install_mode_config(struct service *serv, Boolean installConfig, Boolean installPolicies)
1851{
1852	struct in_addr addr, mask, local_addr, remote_addr;
1853	char	*data;
1854    CFDictionaryRef dict = NULL;
1855    CFMutableArrayRef dicts_to_publish = NULL, dict_names_to_publish = NULL;
1856	int		error, isdefault = 1, len, data_len;
1857	char	*errorstr;
1858	u_int32_t dns, prefix, local_prefix, remote_prefix;
1859	u_int32_t	internal_ip4_address, internal_ip4_netmask;
1860	CFStringRef	strRef, domain_name = NULL;
1861	CFMutableArrayRef split_dns_array = NULL, dns_array = NULL;
1862	int must_prompt;
1863	int unity_splitdns_name_i = 0, unity_split_include_i = 0, unity_local_lan_i = 0, unity_browser_i = 0;
1864
1865	serv->u.ipsec.ping_addr.s_addr = 0;
1866
1867	u_int8_t *modecfg_msg = serv->u.ipsec.modecfg_msg;
1868	u_int32_t modecfg_msglen = serv->u.ipsec.modecfg_msglen;
1869	struct vpnctl_hdr *ctl_hdr = (struct vpnctl_hdr *)modecfg_msg;
1870	if (modecfg_msg == NULL) {
1871		modecfg_msg = serv->u.ipsec.msg;
1872		modecfg_msglen = serv->u.ipsec.msglen;
1873		ctl_hdr = &serv->u.ipsec.msghdr;
1874	}
1875
1876	if (modecfg_msg == NULL) {
1877		return;
1878	}
1879
1880	struct vpnctl_status_phase_change *phase_change_status = ALIGNED_CAST(struct vpnctl_status_phase_change *)modecfg_msg;
1881	struct vpnctl_modecfg_params *modecfg = ALIGNED_CAST(struct vpnctl_modecfg_params *)(modecfg_msg + sizeof(struct vpnctl_status_phase_change));
1882
1883	char *modecfg_data = (char*)modecfg_msg + sizeof(struct vpnctl_status_phase_change) + sizeof(struct vpnctl_modecfg_params);
1884	int modecfg_data_len = ntohs(ctl_hdr->len) - ((sizeof(struct vpnctl_status_phase_change) + sizeof(struct vpnctl_modecfg_params)) -  sizeof(struct vpnctl_hdr));
1885
1886	CFMutableArrayRef policies_array;
1887	CFMutableDictionaryRef policies, policy;
1888
1889	internal_ip4_address = htonl(0);
1890	internal_ip4_netmask = htonl(0xFFFFFFFF);
1891
1892	/* first pass, get mandatory parameters */
1893
1894	int tlen = modecfg_data_len;
1895	char	*dataptr = modecfg_data;
1896    struct isakmp_data attr;
1897
1898	IPSECLOGASLMSG("IPSec Network Configuration started.\n");
1899
1900	while (tlen > 0)
1901	{
1902		int tlv;
1903		u_int16_t type;
1904
1905        memcpy(&attr, dataptr, sizeof(attr));   // Wcast-align fix - memcpy for unbaligned access
1906		type = ntohs(attr.type) & 0x7FFF;
1907		tlv = (type ==  ntohs(attr.type));
1908
1909		switch (type)
1910		{
1911			case INTERNAL_IP4_ADDRESS:
1912                // Wcast-align fix - memcpy for unaligned access
1913                memcpy(&internal_ip4_address, dataptr + sizeof(u_int32_t), sizeof(internal_ip4_address));   // network byte order
1914				addr.s_addr = internal_ip4_address;
1915				IPSECLOGASLMSG("IPSec Network Configuration: INTERNAL-IP4-ADDRESS = %s.\n",
1916							   inet_ntoa(addr));
1917				break;
1918
1919			case INTERNAL_IP4_NETMASK:
1920                // Wcast-align fix - memcpy for unaligned access
1921                memcpy(&internal_ip4_netmask, dataptr + sizeof(u_int32_t), sizeof(internal_ip4_netmask));   // network byte order
1922				addr.s_addr = internal_ip4_netmask;
1923				IPSECLOGASLMSG("IPSec Network Configuration: INTERNAL-IP4-MASK = %s.\n",
1924							   inet_ntoa(addr));
1925				break;
1926
1927			default:
1928				break;
1929		}
1930
1931		if (tlv) {
1932			tlen -= ntohs(attr.lorv);
1933			dataptr += ntohs(attr.lorv);
1934		}
1935
1936		tlen -= sizeof(u_int32_t);
1937		dataptr += sizeof(u_int32_t);
1938
1939	}
1940
1941	if (internal_ip4_address == htonl(0)) {
1942		// ip address is missing
1943		ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Internal IP Address missing from Mode Config packet "));
1944		return;
1945	}
1946
1947	policies = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1948	policies_array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1949
1950	addr.s_addr = modecfg->outer_local_addr;
1951	AddString(policies, kRASPropIPSecLocalAddress, inet_ntoa(addr));
1952	addr.s_addr = phase_change_status->address;
1953	AddString(policies, kRASPropIPSecRemoteAddress, inet_ntoa(addr));
1954
1955	/* second pass, get optional parameters */
1956
1957	tlen = modecfg_data_len;
1958	dataptr = modecfg_data;
1959
1960	while (tlen > 0)
1961	{
1962		int tlv;
1963		u_int16_t type;
1964
1965		memcpy(&attr, dataptr, sizeof(attr));        // Wcast-align fix - memcpy for unaligned access
1966		type = ntohs(attr.type) & 0x7FFF;
1967		tlv = (type ==  ntohs(attr.type));
1968
1969		switch (type)
1970		{
1971			case INTERNAL_IP4_DNS:
1972				if (!dns_array)
1973					dns_array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1974
1975				if (!dns_array)
1976					break;
1977
1978                memcpy(&dns, dataptr + sizeof(u_int32_t), sizeof(u_int32_t));      // Wcast-align fix - memcpy for unaligned access
1979				strRef = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&dns));
1980				if (!strRef)
1981					break;
1982
1983				CFArrayAppendValue(dns_array, strRef);
1984				IPSECLOGASLMSG("IPSec Network Configuration: INTERNAL-IP4-DNS = %s.\n",
1985							   CFStringGetCStringPtr(strRef, kCFStringEncodingMacRoman));
1986				CFRelease(strRef);
1987				break;
1988
1989
1990			default:
1991				break;
1992		}
1993
1994
1995		if (tlv) {
1996			tlen -= ntohs(attr.lorv);
1997			dataptr += ntohs(attr.lorv);
1998		}
1999
2000		tlen -= sizeof(u_int32_t);
2001		dataptr += sizeof(u_int32_t);
2002
2003	}
2004
2005
2006	if (isdefault) {
2007		// default route
2008		policy = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2009
2010		CFDictionarySetValue(policy, kRASPropIPSecPolicyMode, kRASValIPSecPolicyModeTunnel);
2011		CFDictionarySetValue(policy, kRASPropIPSecPolicyDirection, kRASValIPSecPolicyDirectionInOut);
2012		CFDictionarySetValue(policy, kRASPropIPSecPolicyLevel, kRASValIPSecPolicyLevelRequire);
2013
2014		addr.s_addr = internal_ip4_address;
2015		AddString(policy, kRASPropIPSecPolicyLocalAddress, inet_ntoa(addr));
2016		mask.s_addr = ntohl(0xFFFFFFFF /* internal_ip4_netmask */); // VPN client should use 255.255.255.255
2017		for (prefix = 0; mask.s_addr; mask.s_addr<<=1, prefix++);
2018		AddNumber(policy, kRASPropIPSecPolicyLocalPrefix, prefix);
2019		IPSECLOGASLMSG("IPSec Network Configuration: DEFAULT-ROUTE = local-address %s/%d.\n",
2020					   inet_ntoa(addr), prefix);
2021
2022		serv->u.ipsec.ping_addr.s_addr = internal_ip4_address; // will ping our own address, it will hit the (internal_ip4_address --> any) policy
2023
2024		CFDictionarySetValue(policy, kRASPropIPSecPolicyRemoteAddress, CFSTR("0.0.0.0"));
2025		AddNumber(policy, kRASPropIPSecPolicyRemotePrefix, 0);
2026
2027		update_service_route(serv, internal_ip4_address, 0xFFFFFFFF, 0, 0, 0, 0, 0);
2028
2029		CFArrayAppendValue(policies_array, policy);
2030		CFRelease(policy);
2031	}
2032
2033
2034	CFDictionarySetValue(policies, kRASPropIPSecPolicies, policies_array);
2035	CFRelease(policies_array);
2036
2037	if (installPolicies) {
2038		ipsec_log(LOG_DEBUG, CFSTR("IPSec Controller: Mode Config Policies %@"), policies);
2039
2040		if ((error = IPSecInstallPolicies(policies, -1, &errorstr)) < 0) {
2041			ipsec_log(LOG_ERR, CFSTR("IPSec Controller: IPSecInstallPolicies failed '%s'"), errorstr);
2042			CFRelease(policies);
2043			goto fail;
2044		}
2045		serv->u.ipsec.modecfg_policies = (CFMutableDictionaryRef)my_CFRetain(policies);
2046		serv->u.ipsec.modecfg_defaultroute = isdefault;
2047
2048		serv->u.ipsec.inner_local_addr = internal_ip4_address;
2049		serv->u.ipsec.inner_local_mask = internal_ip4_netmask;
2050
2051		/* create the virtual interface */
2052		serv->u.ipsec.kernctl_sock = create_tun_interface(serv->if_name, sizeof(serv->if_name), &serv->if_index, UTUN_FLAGS_NO_INPUT + UTUN_FLAGS_NO_OUTPUT, 0);
2053		if (serv->u.ipsec.kernctl_sock == -1) {
2054			ipsec_log(LOG_ERR, CFSTR("IPSec Controller: cannot create tunnel interface"));
2055			goto fail;
2056		}
2057
2058		if (set_tun_delegate(serv->u.ipsec.kernctl_sock, serv->u.ipsec.lower_interface)) {
2059			ipsec_log(LOG_ERR, CFSTR("IPSec Controller: cannot set delegate interface for tunnel interface"));
2060			goto fail;
2061		}
2062
2063		set_ifmtu(serv->if_name, 1280);
2064		set_ifaddr(serv->if_name, internal_ip4_address, internal_ip4_address,internal_ip4_netmask);
2065
2066		if ((error = racoon_send_cmd_start_ph2(serv->u.ipsec.controlfd, serv->u.ipsec.peer_address.sin_addr.s_addr, policies)) != 0) {
2067			ipsec_log(LOG_ERR, CFSTR("IPSec Controller: racoon_send_cmd_start_ph2 failed '%s'"), errorstr);
2068			goto fail;
2069		}
2070		racoon_trigger_phase2(serv->if_name, &serv->u.ipsec.ping_addr);
2071	}
2072
2073	if (installConfig) {
2074		SCNetworkReachabilityRef	ref;
2075		SCNetworkConnectionFlags	flags;
2076		bool 			is_peer_local;
2077		struct sockaddr_in ip_zeros;
2078
2079		bzero(&ip_zeros, sizeof(ip_zeros));
2080		ip_zeros.sin_len = sizeof(ip_zeros);
2081		ip_zeros.sin_family = AF_INET;
2082
2083		/* check if is peer on our local subnet */
2084		ref = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&serv->u.ipsec.peer_address);
2085		is_peer_local = SCNetworkReachabilityGetFlags(ref, &flags) && (flags & kSCNetworkFlagsIsDirect);
2086
2087#if TARGET_OS_EMBEDDED
2088		if (serv->u.ipsec.lower_interface[0]) {
2089			// Mark interface as cellular based on NWI
2090			serv->u.ipsec.lower_interface_cellular = interface_is_cellular(serv->u.ipsec.lower_interface);
2091			ipsec_log(LOG_INFO, CFSTR("IPSec Controller: lower interface (%s) is%s cellular"), serv->u.ipsec.lower_interface, serv->u.ipsec.lower_interface_cellular ? "" : " not");
2092		} else {
2093			/* Mark interface as cellular based on reachability */
2094			serv->u.ipsec.lower_interface_cellular = SCNetworkReachabilityGetFlags(ref, &flags) && (flags & kSCNetworkReachabilityFlagsIsWWAN);
2095		}
2096#endif
2097
2098		CFRelease(ref);
2099
2100		CFArrayRef includedRoutes = NULL;
2101		CFMutableArrayRef excludedRoutes = NULL;
2102
2103		if (is_peer_local
2104			|| (serv->u.ipsec.lower_gateway.sin_addr.s_addr == 0)) {
2105
2106			if (serv->u.ipsec.lower_interface[0]) {
2107				/* subnet route */
2108				excludedRoutes = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
2109				add_ipv4_route(excludedRoutes, serv->u.ipsec.peer_address.sin_addr.s_addr, INADDR_BROADCAST, 0, TRUE, serv->u.ipsec.lower_interface);
2110			}
2111		}
2112		else {
2113			/* host route */
2114			excludedRoutes = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
2115			add_ipv4_route(excludedRoutes, serv->u.ipsec.peer_address.sin_addr.s_addr, INADDR_BROADCAST, serv->u.ipsec.lower_gateway.sin_addr.s_addr, TRUE, NULL);
2116		}
2117
2118		if (!isdefault) {
2119			addr.s_addr = internal_ip4_address;
2120			if ((includedRoutes = create_ipv4_route_array(serv, policies, addr)) == NULL) {
2121				ipsec_log(LOG_ERR, CFSTR("IPSec Controller: create_ipv4_route_array failed"));
2122			}
2123		}
2124
2125		if (!serv->ne_sm_bridge) {
2126			format_routes_for_cache(serv, &addr, isdefault);
2127		}
2128
2129		dicts_to_publish = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2130		dict_names_to_publish = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2131
2132		dict = create_stateaddr(gDynamicStore, serv->serviceID, serv->if_name, serv->u.ipsec.peer_address.sin_addr.s_addr, internal_ip4_address,internal_ip4_address, internal_ip4_netmask, isdefault, includedRoutes, excludedRoutes);
2133		my_CFRelease(&includedRoutes);
2134		my_CFRelease(&excludedRoutes);
2135		if (dict) {
2136			CFArrayAppendValue(dict_names_to_publish, kSCEntNetIPv4);
2137			CFArrayAppendValue(dicts_to_publish, dict);
2138			CFRelease(dict);
2139		}
2140
2141		if (isdefault) {
2142			dict = create_ipv6_dummy_primary(serv->if_name);
2143			if (dict) {
2144				serv->u.ipsec.dummy_ipv6_installed = 1;
2145				CFArrayAppendValue(dict_names_to_publish, kSCEntNetIPv6);
2146				CFArrayAppendValue(dicts_to_publish, dict);
2147				CFRelease(dict);
2148			}
2149		}
2150
2151		if (dns_array) {
2152
2153			// add split dns array if only domain name was provided by the server
2154			if (!split_dns_array && domain_name) {
2155				split_dns_array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2156				if (split_dns_array) {
2157					CFArrayAppendValue(split_dns_array, domain_name);
2158				}
2159			}
2160
2161			dict = create_dns(gDynamicStore, serv->serviceID, dns_array, domain_name, split_dns_array, FALSE);
2162			if (dict) {
2163				CFArrayAppendValue(dict_names_to_publish, kSCEntNetDNS);
2164				CFArrayAppendValue(dicts_to_publish, dict);
2165				CFRelease(dict);
2166			}
2167		}
2168
2169
2170		if (serv->ne_sm_bridge != NULL) {
2171			ne_sm_bridge_filter_state_dictionaries(serv->ne_sm_bridge, dict_names_to_publish, dicts_to_publish);
2172		}
2173
2174		/* Publish all-at-once */
2175		publish_multiple_dicts(gDynamicStore, serv->serviceID,dict_names_to_publish, dicts_to_publish);
2176		ipsec_log(LOG_DEBUG, CFSTR("IPSec Controller: Published dictionaries to dynamic store."));
2177	}
2178	my_CFRelease(&split_dns_array);
2179	my_CFRelease(&domain_name);
2180	my_CFRelease(&dns_array);
2181	my_CFRelease(&dicts_to_publish);
2182	my_CFRelease(&dict_names_to_publish);
2183	my_CFRelease(&policies);
2184
2185	if (installConfig) {
2186		serv->u.ipsec.modecfg_installed = 1;
2187	}
2188	if (installPolicies) {
2189		serv->u.ipsec.modecfg_policies_installed = 1;
2190	}
2191
2192	IPSECLOGASLMSG("IPSec Network Configuration established.\n");
2193
2194	return;
2195
2196fail:
2197	my_CFRelease(&split_dns_array);
2198	my_CFRelease(&domain_name);
2199	my_CFRelease(&dns_array);
2200	my_CFRelease(&serv->u.ipsec.banner);
2201	my_CFRelease(&dicts_to_publish);
2202	my_CFRelease(&dict_names_to_publish);
2203	my_CFRelease(&policies);
2204
2205	if (serv->u.ipsec.modecfg_policies) {
2206		error = IPSecRemovePolicies(serv->u.ipsec.modecfg_policies, -1,  &errorstr);
2207		my_CFRelease(&serv->u.ipsec.modecfg_policies);
2208
2209	}
2210	if (serv->u.ipsec.modecfg_defaultroute) {
2211		// don't need that since we unpublished the whole dictionary
2212		// unpublish_dictentry(gDynamicStore, serv->serviceID, kSCEntNetIPv4, kSCPropNetOverridePrimary);
2213		serv->u.ipsec.modecfg_defaultroute = 0;
2214	}
2215
2216	my_close(serv->u.ipsec.kernctl_sock);
2217	serv->u.ipsec.kernctl_sock = -1;
2218}
2219
2220/* -----------------------------------------------------------------------------
2221----------------------------------------------------------------------------- */
2222static int unassert_mode_config(struct service *serv)
2223{
2224	if (serv->u.ipsec.modecfg_installed) {
2225		/* we already have a config, so if phase1 is asserted-established stop timer and let racoon take care of the IPSec SAs rekeys */
2226		if (IPSEC_IS_ASSERTED_PHASE1(serv->u.ipsec)) {
2227			if (serv->u.ipsec.timerref) {
2228				CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), serv->u.ipsec.timerref, kCFRunLoopCommonModes);
2229			}
2230			my_CFRelease(&serv->u.ipsec.timerref);
2231		}
2232		return 0;
2233	}
2234	return -1;
2235}
2236
2237/* -----------------------------------------------------------------------------
2238 ----------------------------------------------------------------------------- */
2239int racoon_send_cmd_reconnect(int fd, u_int32_t address)
2240{
2241	u_int8_t					data[256] __attribute__ ((aligned (4))); 		// Wcast-align fix - force alignment
2242	struct vpnctl_cmd_connect	*cmd_reconnect = ALIGNED_CAST(struct vpnctl_cmd_connect *)data;
2243
2244	bzero(cmd_reconnect, sizeof(struct vpnctl_cmd_connect));
2245	cmd_reconnect->hdr.len = htons(sizeof(*cmd_reconnect) - sizeof(cmd_reconnect->hdr));
2246	cmd_reconnect->hdr.msg_type = htons(VPNCTL_CMD_RECONNECT);
2247	cmd_reconnect->address = address;
2248	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: sending RECONNECT to racoon control socket"));
2249	write(fd, cmd_reconnect, sizeof(*cmd_reconnect));
2250	return 0;
2251}
2252
2253/* -----------------------------------------------------------------------------
2254----------------------------------------------------------------------------- */
2255static
2256void racoon_timer(CFRunLoopTimerRef timer, void *info)
2257{
2258	struct service *serv = info;
2259	struct sockaddr_in address;
2260	CFRange			range;
2261	CFDataRef		dataref;
2262
2263	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: racoon_timer expired"));
2264
2265	/* if no contact, try next server */
2266	if (serv->u.ipsec.phase == IPSEC_INITIALIZE || serv->u.ipsec.phase == IPSEC_CONTACT) {
2267
2268		if (serv->u.ipsec.resolvedAddress &&
2269			(serv->u.ipsec.next_address < CFArrayGetCount(serv->u.ipsec.resolvedAddress))) {
2270
2271			dataref = CFArrayGetValueAtIndex(serv->u.ipsec.resolvedAddress, serv->u.ipsec.next_address);
2272			serv->u.ipsec.next_address++;
2273
2274			bzero(&address, sizeof(address));
2275			range.location = 0;
2276			range.length = sizeof(address);
2277			CFDataGetBytes(dataref, range, (UInt8 *)&address);
2278
2279			ipsec_log(LOG_INFO, CFSTR("IPSec Controller: racoon_timer call racoon_restart"));
2280			racoon_restart(serv, &address);
2281			return;
2282		}
2283	}
2284
2285	/* need to resend ping ? */
2286	if (serv->u.ipsec.phase == IPSEC_PHASE1 || IPSEC_IS_ASSERTED_PHASE1(serv->u.ipsec)) {
2287
2288		if (serv->u.ipsec.ping_count > 0) {
2289			serv->u.ipsec.ping_count--;
2290			//printf("timer_resend ping, addr = 0x%s\n", inet_ntoa(serv->u.ipsec.ping_addr));
2291			racoon_trigger_phase2(serv->if_name, &serv->u.ipsec.ping_addr);
2292			if (serv->u.ipsec.timerref) {
2293				CFRunLoopTimerSetNextFireDate(serv->u.ipsec.timerref, CFAbsoluteTimeGetCurrent() + TIMEOUT_PHASE2_PING);
2294			}
2295			return;
2296		}
2297	}
2298
2299	/* need to continue assert ? */
2300	if (IPSEC_IS_ASSERTED_IDLE(serv->u.ipsec)) {
2301		racoon_send_cmd_reconnect(serv->u.ipsec.controlfd, serv->u.ipsec.peer_address.sin_addr.s_addr);
2302		IPSEC_ASSERT_INITIALIZE(serv->u.ipsec);
2303		if (serv->u.ipsec.timerref) {
2304			CFRunLoopTimerSetNextFireDate(serv->u.ipsec.timerref, CFAbsoluteTimeGetCurrent() + TIMEOUT_INITIAL_CONTACT);
2305		}
2306		return;
2307	}
2308
2309	switch (serv->u.ipsec.phase) {
2310		case IPSEC_INITIALIZE:
2311			serv->u.ipsec.laststatus = IPSEC_CONFIGURATION_ERROR;
2312			break;
2313		case IPSEC_CONTACT:
2314			serv->u.ipsec.laststatus = IPSEC_CONNECTION_ERROR;
2315			break;
2316		default:
2317			serv->u.ipsec.laststatus = IPSEC_NEGOTIATION_ERROR;
2318			break;
2319	}
2320	ipsec_stop(serv, 0);
2321
2322}
2323
2324static u_int32_t get_interface_timeout (u_int32_t interface_media)
2325{
2326    u_int32_t scaled_interface_timeout = TIMEOUT_INTERFACE_CHANGE;
2327#if !TARGET_OS_EMBEDDED
2328    // increase the timeout if we're waiting for a wireless interface
2329    if (IFM_TYPE(interface_media) == IFM_IEEE80211) {
2330        scaled_interface_timeout = (TIMEOUT_INTERFACE_CHANGE << 2);
2331    }
2332#endif /* !iPhone */
2333    ipsec_log(LOG_INFO, CFSTR("getting interface (media %x) timeout for ipsec: %d secs"), interface_media, scaled_interface_timeout);
2334    return scaled_interface_timeout;
2335}
2336
2337/* -----------------------------------------------------------------------------
2338----------------------------------------------------------------------------- */
2339static
2340void event_timer(CFRunLoopTimerRef timer, void *info)
2341{
2342	struct service *serv = info;
2343
2344	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: Network change event timer expired"));
2345
2346	IPSecLogVPNInterfaceAddressEvent(__FUNCTION__, NULL, serv->u.ipsec.timeout_lower_interface_change, serv->u.ipsec.lower_interface, &serv->u.ipsec.our_address.sin_addr);
2347
2348	serv->u.ipsec.laststatus = IPSEC_NETWORKCHANGE_ERROR;
2349	ipsec_stop(serv, 0);
2350
2351}
2352
2353
2354/* -----------------------------------------------------------------------------
2355----------------------------------------------------------------------------- */
2356static
2357void racoon_callback(CFSocketRef inref, CFSocketCallBackType type,
2358                     CFDataRef address, const void *data, void *info)
2359{
2360    int 		s = CFSocketGetNative(inref);
2361    int			action = do_nothing;
2362    ssize_t		n;
2363	struct service *serv = info;
2364
2365    /* first read the header part of the message */
2366    if (serv->u.ipsec.msglen < sizeof(struct vpnctl_hdr)) {
2367        n = readn(s, &((u_int8_t *)&serv->u.ipsec.msghdr)[serv->u.ipsec.msglen], sizeof(struct vpnctl_hdr) - serv->u.ipsec.msglen);
2368        switch (n) {
2369            case -1:
2370//	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: racoon_callback, failed to read header, closing"));
2371                action = do_close;
2372                break;
2373            default:
2374                serv->u.ipsec.msglen += n;
2375                if (serv->u.ipsec.msglen == sizeof(struct vpnctl_hdr)) {
2376
2377                    serv->u.ipsec.msgtotallen = serv->u.ipsec.msglen + ntohs(serv->u.ipsec.msghdr.len);
2378                    serv->u.ipsec.msg = my_Allocate(serv->u.ipsec.msgtotallen + 1);
2379                    if (serv->u.ipsec.msg == 0)
2380                        action = do_error;
2381                    else {
2382                        bcopy(&serv->u.ipsec.msghdr, serv->u.ipsec.msg, sizeof(struct vpnctl_hdr));
2383                        // let's end the message with a null byte
2384                        serv->u.ipsec.msg[serv->u.ipsec.msgtotallen] = 0;
2385                    }
2386#if 0
2387					ipsec_log(LOG_INFO, CFSTR("IPSec Controller: racoon_callback, header ="));
2388					ipsec_log(LOG_INFO, CFSTR("IPSec Controller: racoon_callback,   msg_type = 0x%x"), serv->u.ipsec.msghdr.msg_type);
2389					ipsec_log(LOG_INFO, CFSTR("IPSec Controller: racoon_callback,   flags = 0x%x"), serv->u.ipsec.msghdr.flags);
2390					ipsec_log(LOG_INFO, CFSTR("IPSec Controller: racoon_callback,   cookie = 0x%x"), serv->u.ipsec.msghdr.cookie);
2391					ipsec_log(LOG_INFO, CFSTR("IPSec Controller: racoon_callback,   reserved = 0x%x"), serv->u.ipsec.msghdr.reserved);
2392					ipsec_log(LOG_INFO, CFSTR("IPSec Controller: racoon_callback,   result = 0x%x"), serv->u.ipsec.msghdr.result);
2393					ipsec_log(LOG_INFO, CFSTR("IPSec Controller: racoon_callback,   len = %d"), serv->u.ipsec.msghdr.len);
2394#endif
2395              }
2396        }
2397    }
2398
2399    /* first read the data part of the message */
2400    if (serv->u.ipsec.msglen >= sizeof(struct vpnctl_hdr)) {
2401//	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: racoon_callback, len to read = %d"), serv->u.ipsec.msgtotallen - serv->u.ipsec.msglen);
2402
2403        n = readn(s, &serv->u.ipsec.msg[serv->u.ipsec.msglen], serv->u.ipsec.msgtotallen - serv->u.ipsec.msglen);
2404        switch (n) {
2405            case -1:
2406 //	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: racoon_callback, failed to read payload, closing"));
2407               action = do_close;
2408                break;
2409            default:
2410                serv->u.ipsec.msglen += n;
2411                if (serv->u.ipsec.msglen == serv->u.ipsec.msgtotallen) {
2412                    action = do_process;
2413                }
2414        }
2415    }
2416
2417    /* perform action */
2418    switch (action) {
2419        case do_nothing:
2420            break;
2421        case do_error:
2422        case do_close:
2423            /* connection closed by client */
2424			ipsec_log(LOG_INFO, CFSTR("IPSec Controller: connection closed by client, call ipsec_stop"));
2425			serv->u.ipsec.laststatus = IPSEC_GENERIC_ERROR;
2426			ipsec_stop(serv, 0);
2427            break;
2428
2429        case do_process:
2430            // process client request
2431            process_racoon_msg(serv);
2432            my_Deallocate(serv->u.ipsec.msg, serv->u.ipsec.msgtotallen + 1);
2433            serv->u.ipsec.msg = 0;
2434            serv->u.ipsec.msglen = 0;
2435            serv->u.ipsec.msgtotallen = 0;
2436            break;
2437    }
2438}
2439
2440static int
2441IPSecCheckVPNInterfaceOrServiceUnrecoverable (SCDynamicStoreRef dynamicStoreRef,
2442											  const char            *location,
2443											  struct kern_event_msg *ev_msg,
2444											  char                  *interface_buf)
2445{
2446	//SCDynamicStoreRef dynamicStoreRef = (SCDynamicStoreRef)dynamicStore;
2447
2448	// return 1, if this is a delete event, and;
2449	// TODO: add support for IPv6 <rdar://problem/5920237>
2450	// walk Setup:/Network/Service/* and check if there are service entries referencing this interface. e.g. Setup:/Network/Service/44DB8790-0177-4F17-8D4E-37F9413D1D87/Interface:DeviceName == interface, other_serv_found = 1
2451	// Setup:/Network/Interface/"interface"/AirPort:'PowerEnable' == 0 || Setup:/Network/Interface/"interface"/IPv4 is missing, interf_down = 1
2452	if (!dynamicStoreRef)
2453		syslog(LOG_DEBUG, "%s: invalid SCDynamicStore reference", location);
2454
2455	if (dynamicStoreRef &&
2456	    (ev_msg->event_code == KEV_INET_ADDR_DELETED || ev_msg->event_code == KEV_INET_CHANGED_ADDR)) {
2457		CFStringRef       interf_key;
2458		CFMutableArrayRef interf_keys;
2459		CFStringRef       pattern;
2460		CFMutableArrayRef patterns;
2461		CFDictionaryRef   dict = NULL;
2462		CFIndex           i;
2463		const void *      keys_q[128];
2464		const void **     keys = keys_q;
2465		const void *      values_q[128];
2466		const void **     values = values_q;
2467		CFIndex           n;
2468		CFStringRef       vpn_if;
2469		int               other_serv_found = 0, interf_down = 0;
2470
2471		vpn_if = CFStringCreateWithCStringNoCopy(NULL,
2472												 interface_buf,
2473												 kCFStringEncodingASCII,
2474												 kCFAllocatorNull);
2475		if (!vpn_if) {
2476			// if we could not initialize interface CFString
2477			syslog(LOG_NOTICE, "%s: failed to initialize interface CFString", location);
2478			goto done;
2479		}
2480
2481		interf_keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2482		patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2483		// get Setup:/Network/Interface/<vpn_if>/Airport
2484		interf_key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
2485																   kSCDynamicStoreDomainSetup,
2486																   vpn_if,
2487																   kSCEntNetAirPort);
2488		CFArrayAppendValue(interf_keys, interf_key);
2489		CFRelease(interf_key);
2490		// get State:/Network/Interface/<vpn_if>/Airport
2491		interf_key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
2492																   kSCDynamicStoreDomainState,
2493																   vpn_if,
2494																   kSCEntNetAirPort);
2495		CFArrayAppendValue(interf_keys, interf_key);
2496		CFRelease(interf_key);
2497		// get Setup:/Network/Service/*/Interface
2498		pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
2499															  kSCDynamicStoreDomainSetup,
2500															  kSCCompAnyRegex,
2501															  kSCEntNetInterface);
2502		CFArrayAppendValue(patterns, pattern);
2503		CFRelease(pattern);
2504		// get Setup:/Network/Service/*/IPv4
2505		pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
2506															  kSCDynamicStoreDomainSetup,
2507															  kSCCompAnyRegex,
2508															  kSCEntNetIPv4);
2509		CFArrayAppendValue(patterns, pattern);
2510		CFRelease(pattern);
2511		dict = SCDynamicStoreCopyMultiple(dynamicStoreRef, interf_keys, patterns);
2512		CFRelease(interf_keys);
2513		CFRelease(patterns);
2514
2515		if (!dict) {
2516			// if we could not access the SCDynamicStore
2517			syslog(LOG_NOTICE, "%s: failed to initialize SCDynamicStore dictionary", location);
2518			CFRelease(vpn_if);
2519			goto done;
2520		}
2521		// look for the service which matches the provided prefixes
2522		n = CFDictionaryGetCount(dict);
2523		if (n <= 0) {
2524			syslog(LOG_NOTICE, "%s: empty SCDynamicStore dictionary", location);
2525			CFRelease(vpn_if);
2526			goto done;
2527		}
2528		if (n > (CFIndex)(sizeof(keys_q) / sizeof(CFTypeRef))) {
2529			keys   = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
2530			values = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
2531		}
2532		CFDictionaryGetKeysAndValues(dict, keys, values);
2533		for (i=0; i < n; i++) {
2534			CFStringRef     s_key  = (CFStringRef)keys[i];
2535			CFDictionaryRef s_dict = (CFDictionaryRef)values[i];
2536			CFStringRef     s_if;
2537
2538			if (!isA_CFString(s_key) || !isA_CFDictionary(s_dict)) {
2539				continue;
2540			}
2541
2542			if (CFStringHasSuffix(s_key, kSCEntNetInterface)) {
2543				// is a Service Interface entity
2544				s_if = CFDictionaryGetValue(s_dict, kSCPropNetInterfaceDeviceName);
2545				if (isA_CFString(s_if) && CFEqual(vpn_if, s_if)) {
2546					CFArrayRef        components;
2547					CFStringRef       serviceIDRef = NULL, serviceKey = NULL;
2548					CFPropertyListRef serviceRef = NULL;
2549
2550					other_serv_found = 1;
2551					// extract service ID
2552					components = CFStringCreateArrayBySeparatingStrings(NULL, s_key, CFSTR("/"));
2553					if (CFArrayGetCount(components) > 3) {
2554						serviceIDRef = CFArrayGetValueAtIndex(components, 3);
2555						//if (new key) Setup:/Network/Service/service_id/IPv4 is missing, then interf_down = 1
2556						serviceKey = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainSetup, serviceIDRef, kSCEntNetIPv4);
2557						if (!serviceKey ||
2558						    !(serviceRef = CFDictionaryGetValue(dict, serviceKey))) {
2559							syslog(LOG_NOTICE, "%s: detected disabled IPv4 Config", location);
2560							interf_down = 1;
2561						}
2562						if (serviceKey) CFRelease(serviceKey);
2563					}
2564					if (components) CFRelease(components);
2565					if (interf_down) break;
2566				}
2567				continue;
2568			} else if (CFStringHasSuffix(s_key, kSCEntNetAirPort)) {
2569				// Interface/<vpn_if>/Airport entity
2570				if (CFStringHasPrefix(s_key, kSCDynamicStoreDomainSetup)) {
2571					CFBooleanRef powerEnable = CFDictionaryGetValue(s_dict, SC_AIRPORT_POWERENABLED_KEY);
2572					if (isA_CFBoolean(powerEnable) &&
2573					    CFEqual(powerEnable, kCFBooleanFalse)) {
2574						syslog(LOG_NOTICE, "%s: detected AirPort, PowerEnable == FALSE", location);
2575						interf_down = 1;
2576						break;
2577					}
2578				} else if (CFStringHasPrefix(s_key, kSCDynamicStoreDomainState)) {
2579					UInt16      temp;
2580					CFNumberRef airStatus = CFDictionaryGetValue(s_dict, SC_AIRPORT_POWERSTATUS_KEY);
2581					if (isA_CFNumber(airStatus) &&
2582					    CFNumberGetValue(airStatus, kCFNumberShortType, &temp)) {
2583						if (temp ==0) {
2584							syslog(LOG_NOTICE, "%s: detected AirPort, PowerStatus == 0", location);
2585						}
2586					}
2587				}
2588				continue;
2589			}
2590		}
2591		if (vpn_if) CFRelease(vpn_if);
2592		if (keys != keys_q) {
2593			CFAllocatorDeallocate(NULL, keys);
2594			CFAllocatorDeallocate(NULL, values);
2595		}
2596		done :
2597		if (dict) CFRelease(dict);
2598
2599		return (other_serv_found == 0 || interf_down == 1);
2600	}
2601	return 0;
2602}
2603
2604static int
2605IPSecCheckVPNInterfaceAddressChange (int                    transport_down,
2606                                     struct kern_event_msg *ev_msg,
2607                                     char                  *interface_buf,
2608                                     struct in_addr        *our_address,
2609                                     struct service        *serv)
2610{
2611    struct kev_in_data *inetdata;
2612
2613    /* if transport is still down: ignore deletes, and check if the underlying interface's address has changed (ignore link-local addresses) */
2614    if (transport_down &&
2615        (ev_msg->event_code == KEV_INET_NEW_ADDR || ev_msg->event_code == KEV_INET_CHANGED_ADDR)) {
2616 		inetdata = (struct kev_in_data *) &ev_msg->event_data[0];
2617#if 0
2618        syslog(LOG_NOTICE, "%s: checking for interface address change. underlying %s, old-addr %x, new-addr %x\n",
2619               __FUNCTION__, interface_buf, our_address->s_addr, inetdata->ia_addr.s_addr);
2620#endif
2621        /* check if address changed */
2622        if (our_address->s_addr != inetdata->ia_addr.s_addr &&
2623            !IN_LINKLOCAL(ntohl(inetdata->ia_addr.s_addr))) {
2624            return 1;
2625        }
2626        // check to see if network has changed (despite the address)
2627        if (DID_VPN_LOCATIONCHANGE(serv)) {
2628            syslog(LOG_NOTICE, "%s: the underlying interface has changed networks\n",
2629                   __FUNCTION__);
2630            return 1;
2631        }
2632    }
2633
2634    return 0;
2635}
2636
2637static int
2638IPSecCheckVPNInterfaceAddressAlternate (int                    transport_down,
2639                                        struct kern_event_msg *ev_msg,
2640                                        char                  *interface_buf)
2641{
2642    struct kev_in_data *inetdata;
2643
2644    /* if transport is still down: ignore deletes, and check if any interface address has alternative address */
2645    if (transport_down &&
2646        (ev_msg->event_code == KEV_INET_NEW_ADDR || ev_msg->event_code == KEV_INET_CHANGED_ADDR)) {
2647 		inetdata = (struct kev_in_data *) &ev_msg->event_data[0];
2648#if 0
2649        syslog(LOG_NOTICE, "%s: checking for alternate interface. underlying %s, new-addr %x\n",
2650               __FUNCTION__, interface_buf, inetdata->ia_addr.s_addr);
2651#endif
2652        /* check if address changed */
2653        if (!IN_LINKLOCAL(ntohl(inetdata->ia_addr.s_addr))) {
2654            return 1;
2655        }
2656    }
2657
2658    return 0;
2659}
2660
2661void
2662ipsec_network_event(struct service *serv, struct kern_event_msg *ev_msg)
2663{
2664	CFRunLoopTimerContext context = { 0, serv, NULL, NULL, NULL };
2665	int found;
2666	struct ifaddrs *ifap = NULL;
2667    char ev_if[32];
2668	struct kev_in_data *inetdata;
2669
2670	inetdata = (struct kev_in_data *) &ev_msg->event_data[0];
2671	IPSecLogVPNInterfaceAddressEvent(__FUNCTION__, ev_msg, serv->u.ipsec.timeout_lower_interface_change, serv->u.ipsec.lower_interface, &serv->u.ipsec.our_address.sin_addr);
2672
2673	// If the configuration is On Demand, switch from Cell to WiFi
2674	if (serv->ne_sm_bridge != NULL &&
2675		serv->flags & FLAG_SETUP_ONDEMAND &&
2676		serv->u.ipsec.lower_interface_cellular) {
2677		Boolean hasPrimaryInterface = FALSE;
2678		Boolean isCellular = primary_interface_is_cellular(&hasPrimaryInterface);
2679		if (hasPrimaryInterface && !isCellular) {
2680			ipsec_log(LOG_INFO, CFSTR("IPSec Controller: Disconnecting tunnel over cellular in favor of better interface"));
2681			serv->u.ipsec.laststatus = IPSEC_NETWORKCHANGE_ERROR;
2682			ipsec_stop(serv, 0);
2683			return;
2684		}
2685	}
2686
2687	switch (ev_msg->event_code) {
2688		case KEV_INET_NEW_ADDR:
2689		case KEV_INET_CHANGED_ADDR:
2690		case KEV_INET_ADDR_DELETED:
2691			snprintf(ev_if, sizeof(ev_if), "%s%d", inetdata->link_data.if_name, inetdata->link_data.if_unit);
2692			// check if changes occured on the interface we are using
2693			if (!strncmp(ev_if, serv->u.ipsec.lower_interface, sizeof(serv->u.ipsec.lower_interface))) {
2694				if (inetdata->link_data.if_family == APPLE_IF_FAM_PPP) {
2695					// disconnect immediately
2696					ipsec_log(LOG_INFO, CFSTR("IPSec Controller: Network changed on underlying PPP interface"));
2697					serv->u.ipsec.laststatus = IPSEC_NETWORKCHANGE_ERROR;
2698					ipsec_stop(serv, 0);
2699				}
2700				else {
2701
2702					/* check if address still exist */
2703					found = 0;
2704					if (getifaddrs(&ifap) == 0) {
2705						struct ifaddrs *ifa;
2706						for (ifa = ifap; ifa && !found ; ifa = ifa->ifa_next) {
2707							found = (ifa->ifa_name
2708									&& ifa->ifa_addr
2709									&& !strncmp(ifa->ifa_name, serv->u.ipsec.lower_interface, sizeof(serv->u.ipsec.lower_interface))
2710									&& ifa->ifa_addr->sa_family == AF_INET
2711									&& (ALIGNED_CAST(struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == serv->u.ipsec.our_address.sin_addr.s_addr);
2712						}
2713						freeifaddrs(ifap);
2714					}
2715
2716					if (found) {
2717						// no meaningful change, or address came back. Cancel timer if it was on.
2718						if (serv->u.ipsec.interface_timerref) {
2719							ipsec_updatephase(serv, IPSEC_RUNNING);
2720							ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Network changed, address came back on underlying interface, cancel timer"));
2721							CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), serv->u.ipsec.interface_timerref, kCFRunLoopCommonModes);
2722							my_CFRelease(&serv->u.ipsec.interface_timerref);
2723
2724							// check to see if network has changed (despite the address)
2725							if (DISCONNECT_VPN_IFLOCATIONCHANGED(serv)) {
2726								ipsec_log(LOG_ERR, CFSTR("IPSec Controller: the underlying interface %s network changed."),
2727										serv->u.ipsec.lower_interface);
2728								serv->u.ipsec.laststatus = IPSEC_NETWORKCHANGE_ERROR;
2729								ipsec_stop(serv, 0);
2730								break;
2731							}
2732							if (serv->flags & FLAG_ONDEMAND) {
2733								racoon_send_cmd_start_dpd(serv->u.ipsec.controlfd, serv->u.ipsec.peer_address.sin_addr.s_addr);
2734								serv->u.ipsec.awaiting_peer_resp = 1;
2735							} else {
2736								ipsec_log(LOG_INFO, CFSTR("IPSec Controller: asserting connection"));
2737								racoon_send_cmd_assert(serv);
2738							}
2739						}
2740					}
2741					else {
2742						// quick exit if there has been an unrecoverable change in interface/service
2743						if (IPSecCheckVPNInterfaceOrServiceUnrecoverable(gDynamicStore,
2744									__FUNCTION__,
2745									ev_msg,
2746									serv->u.ipsec.lower_interface))
2747						{
2748							ipsec_log(LOG_ERR, CFSTR("IPSec Controller: the underlying interface/service has changed unrecoverably."));
2749							serv->u.ipsec.laststatus = IPSEC_NETWORKCHANGE_ERROR;
2750							ipsec_stop(serv, 0);
2751							break;
2752						}
2753
2754						// no address, arm timer if not there
2755						if (!serv->u.ipsec.interface_timerref) {
2756							ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Network changed, address disappeared on underlying interface, install timer %d secs"), serv->u.ipsec.timeout_lower_interface_change);
2757							serv->u.ipsec.interface_timerref = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + serv->u.ipsec.timeout_lower_interface_change, FAR_FUTURE, 0, 0, event_timer, &context);
2758							if (!serv->u.ipsec.interface_timerref) {
2759								ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Network changed, cannot create RunLoop timer"));
2760								// disconnect immediately
2761								serv->u.ipsec.laststatus = IPSEC_NETWORKCHANGE_ERROR;
2762								ipsec_stop(serv, 0);
2763								break;
2764							}
2765							ipsec_updatephase(serv, IPSEC_WAITING);
2766							CFRunLoopAddTimer(CFRunLoopGetCurrent(), serv->u.ipsec.interface_timerref, kCFRunLoopCommonModes);
2767							if (serv->u.ipsec.port_mapping_timerref) {
2768								CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), serv->u.ipsec.port_mapping_timerref, kCFRunLoopCommonModes);
2769								my_CFRelease(&serv->u.ipsec.port_mapping_timerref);
2770							}
2771							(void)DISCONNECT_VPN_IFLOCATIONCHANGED(serv);
2772						} else {
2773							// transport is still down: check if there was a valid address change
2774							if (IPSecCheckVPNInterfaceAddressChange(serv->u.ipsec.phase == IPSEC_WAITING,
2775										/* && serv->u.ipsec.interface_timerref, */
2776										ev_msg,
2777										serv->u.ipsec.lower_interface,
2778										&serv->u.ipsec.our_address.sin_addr,
2779										serv))
2780							{
2781								// disconnect immediately
2782								ipsec_log(LOG_ERR, CFSTR("IPSec Controller: the underlying interface %s address changed."),
2783										serv->u.ipsec.lower_interface);
2784								serv->u.ipsec.laststatus = IPSEC_NETWORKCHANGE_ERROR;
2785								ipsec_stop(serv, 0);
2786							} else {
2787								(void)DISCONNECT_VPN_IFLOCATIONCHANGED(serv);
2788							}
2789						}
2790					}
2791				}
2792			} else {
2793				if (IPSecCheckVPNInterfaceAddressAlternate((serv->u.ipsec.phase == IPSEC_WAITING && serv->u.ipsec.interface_timerref), ev_msg, serv->u.ipsec.lower_interface))
2794				{
2795					ipsec_log(LOG_ERR, CFSTR("IPSec Controller: an alternative interface %s was detected while the underlying interface %s was down."), ev_if, serv->u.ipsec.lower_interface);
2796					serv->u.ipsec.laststatus = IPSEC_NETWORKCHANGE_ERROR;
2797					ipsec_stop(serv, 0);
2798				}
2799			}
2800			break;
2801	}
2802}
2803
2804/* -----------------------------------------------------------------------------
2805----------------------------------------------------------------------------- */
2806static
2807void event_callback(CFSocketRef inref, CFSocketCallBackType type,
2808                     CFDataRef address, const void *data, void *info)
2809{
2810	int s = CFSocketGetNative(inref);
2811	struct service *serv = info;
2812	char buf[256] __attribute__ ((aligned(4))); 		// Wcast-align fix - force alignment
2813	struct kern_event_msg *ev_msg;
2814
2815	if (recv(s, &buf, sizeof(buf), 0) != -1) {
2816		ev_msg = ALIGNED_CAST(struct kern_event_msg *) &buf;
2817		ipsec_network_event(serv, ev_msg);
2818	}
2819}
2820
2821/* -----------------------------------------------------------------------------
2822----------------------------------------------------------------------------- */
2823static int racoon_create_socket(struct service *serv)
2824{
2825    int			flags;
2826    CFRunLoopSourceRef	rls;
2827    CFSocketContext	context = { 0, serv, NULL, NULL, NULL };
2828	struct sockaddr_un	sun;
2829
2830	serv->u.ipsec.controlfd = socket(PF_LOCAL, SOCK_STREAM, 0);
2831	if (serv->u.ipsec.controlfd < 0) {
2832		ipsec_log(LOG_ERR, CFSTR("IPSec Controller: cannot create racoon control socket (errno = %d) "), errno);
2833		goto fail;
2834	}
2835
2836	bzero(&sun, sizeof(sun));
2837	sun.sun_family = AF_LOCAL;
2838	strncpy(sun.sun_path, "/var/run/vpncontrol.sock", sizeof(sun.sun_path));
2839
2840	if (connect(serv->u.ipsec.controlfd, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
2841		ipsec_log(LOG_ERR, CFSTR("IPSec Controller: cannot connect racoon control socket (errno = %d)"), errno);
2842		goto fail;
2843	}
2844
2845    if ((flags = fcntl(serv->u.ipsec.controlfd, F_GETFL)) == -1
2846	|| fcntl(serv->u.ipsec.controlfd, F_SETFL, flags | O_NONBLOCK) == -1) {
2847        ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Couldn't set client socket in non-blocking mode, errno = %d"), errno);
2848    }
2849
2850    if ((serv->u.ipsec.controlref = CFSocketCreateWithNative(NULL, serv->u.ipsec.controlfd,
2851                    kCFSocketReadCallBack, racoon_callback, &context)) == 0) {
2852        goto fail;
2853    }
2854    if ((rls = CFSocketCreateRunLoopSource(NULL, serv->u.ipsec.controlref, 0)) == 0)
2855        goto fail;
2856
2857    CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
2858    CFRelease(rls);
2859
2860    return 0;
2861
2862fail:
2863	if (serv->u.ipsec.controlref) {
2864		CFSocketInvalidate(serv->u.ipsec.controlref);
2865		CFRelease(serv->u.ipsec.controlref);
2866	}
2867	else
2868		if (serv->u.ipsec.controlfd >= 0) {
2869			close(serv->u.ipsec.controlfd);
2870	}
2871	serv->u.ipsec.controlref = 0;
2872	serv->u.ipsec.controlfd = -1;
2873
2874    return -1;
2875}
2876
2877/* -----------------------------------------------------------------------------
2878----------------------------------------------------------------------------- */
2879static
2880void dns_start_query_cf_callback(CFMachPortRef port, void *msg, CFIndex size, void *info)
2881{
2882	struct service	*serv = (struct service *)info;
2883
2884	if (port != serv->u.ipsec.dnsPort) {
2885		// we've received a callback on the async DNS port but since the
2886		// associated CFMachPort doesn't match than the request must have
2887		// already been cancelled.
2888		return;
2889	}
2890
2891	CFMachPortInvalidate(serv->u.ipsec.dnsPort);
2892	CFRelease(serv->u.ipsec.dnsPort);
2893	serv->u.ipsec.dnsPort = NULL;
2894
2895	getaddrinfo_async_handle_reply(msg);
2896	return;
2897}
2898
2899/* -----------------------------------------------------------------------------
2900----------------------------------------------------------------------------- */
2901static
2902void dns_start_query_callback(int32_t status, struct addrinfo *res, void *context)
2903{
2904	struct service *serv		= (struct service *)context;
2905	struct addrinfo				*resP;
2906	CFDataRef					dataref;
2907	struct sockaddr_in			address;
2908
2909	if ((status == 0) && (res != NULL)) {
2910
2911		CFMutableArrayRef	addresses;
2912		CFRange		range;
2913
2914		addresses = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2915		range.location = 0;
2916		range.length = 0;
2917
2918		for (resP = res; resP; resP = resP->ai_next) {
2919			CFDataRef	newAddress;
2920
2921			/* make sure it will fit... */
2922			if (resP->ai_addr->sa_len > sizeof(struct sockaddr_in))
2923				continue;
2924
2925			newAddress = CFDataCreate(NULL, (void *)resP->ai_addr, resP->ai_addr->sa_len);
2926			if (newAddress != NULL) {
2927				if (!CFArrayContainsValue(addresses, range, newAddress)) {
2928					CFArrayAppendValue(addresses, newAddress);
2929					range.length++;
2930				}
2931				CFRelease(newAddress);
2932			}
2933		}
2934
2935		/* save the resolved address[es] */
2936		my_CFRelease(&serv->u.ipsec.resolvedAddress);
2937		serv->u.ipsec.resolvedAddress      = addresses;
2938		serv->u.ipsec.resolvedAddressError = NETDB_SUCCESS;
2939
2940		ipsec_log(LOG_DEBUG, CFSTR("IPSec Controller: dns reply: resolvedAddress %@"), serv->u.ipsec.resolvedAddress);
2941
2942		if (!CFArrayGetCount(serv->u.ipsec.resolvedAddress)) {
2943			ipsec_log(LOG_INFO, CFSTR("IPSec Controller: dns reply: no IPv4 address in reply"));
2944			goto fail;
2945		}
2946
2947		/* get the first address and start racoon */
2948		dataref = CFArrayGetValueAtIndex(serv->u.ipsec.resolvedAddress, 0);
2949		if (!dataref || CFDataGetLength(dataref) < sizeof(address)) {
2950			ipsec_log(LOG_INFO, CFSTR("IPSec Controller: dns reply: failed to get elem %d from addr array"),
2951			      serv->u.ipsec.next_address);
2952			goto fail;
2953		}
2954		bzero(&address, sizeof(address));
2955		range.location = 0;
2956		range.length = sizeof(address);
2957		CFDataGetBytes(dataref, range, (UInt8 *)&address);
2958		serv->u.ipsec.next_address = 1;
2959
2960		racoon_restart(serv, &address);
2961		goto done;
2962	}
2963	else {
2964
2965		ipsec_log(LOG_INFO, CFSTR("IPSec Controller: dns reply: getaddrinfo() failed: %s"), gai_strerror(status));
2966		goto fail;
2967	}
2968
2969fail:
2970	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: dns reply: Stopping service"));
2971	serv->u.ipsec.laststatus = IPSEC_RESOLVEADDRESS_ERROR;
2972	ipsec_stop(serv, 0);
2973	/* save the error associated with the attempt to resolve the name */
2974	serv->u.ipsec.resolvedAddress      = CFRetain(kCFNull);
2975	serv->u.ipsec.resolvedAddressError = status;
2976
2977done:
2978	ipsec_log(LOG_DEBUG, CFSTR("IPSec Controller: dns reply: done"));
2979	if (res != NULL)
2980		freeaddrinfo(res);
2981
2982}
2983
2984/* -----------------------------------------------------------------------------
2985----------------------------------------------------------------------------- */
2986static
2987int dns_start_query(struct service *serv, char *name)
2988{
2989	int					error;
2990	struct addrinfo		hints;
2991	mach_port_t			port;
2992	CFMachPortContext	context		= { 0, serv, NULL, NULL, NULL };
2993	CFRunLoopSourceRef	rls;
2994
2995	gettimeofday(&serv->u.ipsec.dnsQueryStart, NULL);
2996
2997	bzero(&hints, sizeof(hints));
2998	hints.ai_flags = AI_ADDRCONFIG;
2999	hints.ai_family = PF_INET;	/* only IPv4 */
3000#ifdef	AI_PARALLEL
3001	hints.ai_flags |= AI_PARALLEL;
3002#endif	/* AI_PARALLEL */
3003
3004	error = getaddrinfo_async_start(&port, name, NULL, &hints,
3005					dns_start_query_callback, (void *)serv);
3006	if (error != 0) {
3007		/* save the error associated with the attempt to resolve the name */
3008		dns_start_query_callback(error, NULL, (void *)serv);
3009		return -1;
3010	}
3011
3012	serv->u.ipsec.dnsPort = _SC_CFMachPortCreateWithPort("PPPController/DNS", port, dns_start_query_cf_callback, &context);
3013	if ( serv->u.ipsec.dnsPort ){
3014		rls = CFMachPortCreateRunLoopSource(NULL, serv->u.ipsec.dnsPort, 0);
3015		CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopCommonModes);
3016		CFRelease(rls);
3017	}
3018
3019	return 0;
3020}
3021
3022/* -----------------------------------------------------------------------------
3023----------------------------------------------------------------------------- */
3024int racoon_send_cmd_xauthinfo(int fd, u_int32_t address, struct isakmp_xauth *isakmp_array, int isakmp_nb)
3025{
3026	u_int8_t						*data, *p;
3027	struct vpnctl_cmd_xauth_info	*cmd_xauth_info;
3028	int								i, totlen = sizeof(struct vpnctl_cmd_xauth_info);
3029
3030	for (i = 0; i < isakmp_nb; i++) {
3031		totlen += sizeof(u_int32_t) + (isakmp_array[i].str ? CFStringGetLength(isakmp_array[i].str) : 0);
3032	}
3033
3034	data = malloc(totlen);
3035	if (!data) {
3036		return -1;
3037	}
3038
3039	cmd_xauth_info = ALIGNED_CAST(struct vpnctl_cmd_xauth_info *)data;
3040	bzero(cmd_xauth_info, sizeof(struct vpnctl_cmd_xauth_info));
3041	cmd_xauth_info->hdr.msg_type = htons(VPNCTL_CMD_XAUTH_INFO);
3042	cmd_xauth_info->hdr.len = htons(totlen - sizeof(struct vpnctl_hdr));
3043	cmd_xauth_info->address = address;
3044
3045	p = data + sizeof(struct vpnctl_cmd_xauth_info);
3046
3047	for (i = 0; i < isakmp_nb; i++) {
3048		struct isakmp_data d;
3049
3050		CFIndex olen, len = (isakmp_array[i].str ? CFStringGetLength(isakmp_array[i].str) : 0);
3051		CFRange range;
3052		range.location = 0;
3053		range.length = len;
3054
3055		d.type = htons(isakmp_array[i].type);
3056		d.lorv = htons(len);
3057		memcpy(p, &d, sizeof(struct isakmp_data));      // Wcast-align fix - memcpy for unaligned access
3058		p += sizeof(u_int32_t);		// skip isakmp_data
3059		if (len) {
3060			CFStringGetBytes(isakmp_array[i].str, range, kCFStringEncodingUTF8, 0, false, p, len, &olen);
3061			p += len;
3062		}
3063	}
3064
3065	write(fd, data, totlen);
3066
3067	IPSECLOGASLMSG("IPSec sending Extended Authentication.\n");
3068
3069	free(data);
3070	return 0;
3071}
3072
3073
3074/* -----------------------------------------------------------------------------
3075----------------------------------------------------------------------------- */
3076int racoon_send_cmd_connect(int fd, u_int32_t address)
3077{
3078	u_int8_t					data[256] __attribute__ ((aligned (4))); 		// Wcast-align fix - force alignment
3079	struct vpnctl_cmd_connect	*cmd_connect = ALIGNED_CAST(struct vpnctl_cmd_connect *)data;
3080
3081	bzero(cmd_connect, sizeof(struct vpnctl_cmd_connect));
3082	cmd_connect->hdr.len = htons(sizeof(struct vpnctl_cmd_connect) - sizeof(struct vpnctl_hdr));
3083	cmd_connect->hdr.msg_type = htons(VPNCTL_CMD_CONNECT);
3084	cmd_connect->address = address;
3085	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: sending CONNECT to racoon control socket"));
3086	write(fd, cmd_connect, sizeof(struct vpnctl_cmd_connect));
3087	IPSECLOGASLMSG("IPSec Phase1 starting.\n"); // connect command triggers phase1
3088	return 0;
3089}
3090
3091/* -----------------------------------------------------------------------------
3092----------------------------------------------------------------------------- */
3093int racoon_send_cmd_disconnect(int fd, u_int32_t address)
3094{
3095	u_int8_t					data[256] __attribute__ ((aligned (4))); 		// Wcast-align fix - force alignment
3096	struct vpnctl_cmd_connect	*cmd_connect = ALIGNED_CAST(struct vpnctl_cmd_connect *)data;
3097
3098	bzero(cmd_connect, sizeof(struct vpnctl_cmd_connect));
3099	cmd_connect->hdr.len = htons(sizeof(struct vpnctl_cmd_connect) - sizeof(struct vpnctl_hdr));
3100	cmd_connect->hdr.msg_type = htons(VPNCTL_CMD_DISCONNECT);
3101	cmd_connect->address = address;
3102	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: sending DISCONNECT to racoon control socket, address 0x%x"), ntohl(address));
3103	write(fd, cmd_connect, sizeof(struct vpnctl_cmd_connect));
3104	return 0;
3105}
3106
3107/* -----------------------------------------------------------------------------
3108 ----------------------------------------------------------------------------- */
3109int racoon_send_cmd_start_dpd(int fd, u_int32_t address)
3110{
3111	u_int8_t					data[256] __attribute__ ((aligned (4))); 		// Wcast-align fix - force alignment
3112	struct vpnctl_cmd_start_dpd	*cmd_start_dpd = ALIGNED_CAST(struct vpnctl_cmd_start_dpd *)data;
3113
3114	bzero(cmd_start_dpd, sizeof(struct vpnctl_cmd_start_dpd));
3115	cmd_start_dpd->hdr.len = htons(sizeof(struct vpnctl_cmd_start_dpd) - sizeof(struct vpnctl_hdr));
3116	cmd_start_dpd->hdr.msg_type = htons(VPNCTL_CMD_START_DPD);
3117	cmd_start_dpd->address = address;
3118	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: sending START_DPD to racoon control socket"));
3119	write(fd, cmd_start_dpd, sizeof(struct vpnctl_cmd_start_dpd));
3120	return 0;
3121}
3122
3123
3124/* -----------------------------------------------------------------------------
3125----------------------------------------------------------------------------- */
3126int racoon_send_cmd_bind(int fd, u_int32_t address, char *version)
3127{
3128	u_int8_t					data[256] __attribute__ ((aligned (4))); 		// Wcast-align fix - force alignment
3129	struct vpnctl_cmd_bind	*cmd_bind = ALIGNED_CAST(struct vpnctl_cmd_bind *)data;
3130	int vers_len = 0;
3131
3132	if (version)
3133		vers_len = strlen(version);
3134
3135	bzero(cmd_bind, sizeof(struct vpnctl_cmd_bind));
3136	cmd_bind->hdr.len = htons(sizeof(struct vpnctl_cmd_bind) - sizeof(struct vpnctl_hdr) + vers_len);
3137	cmd_bind->hdr.msg_type = htons(VPNCTL_CMD_BIND);
3138	cmd_bind->address = address;
3139	cmd_bind->vers_len = htons(vers_len);
3140	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: sending BIND to racoon control socket"));
3141	write(fd, cmd_bind, sizeof(struct vpnctl_cmd_bind));
3142	if (vers_len)
3143		write(fd, version, vers_len);
3144	return 0;
3145}
3146
3147/* -----------------------------------------------------------------------------
3148----------------------------------------------------------------------------- */
3149int racoon_send_cmd_unbind(int fd, u_int32_t address)
3150{
3151	u_int8_t					data[256] __attribute__ ((aligned (4))); 		// Wcast-align fix - force alignment
3152	struct vpnctl_cmd_unbind	*cmd_unbind = ALIGNED_CAST(struct vpnctl_cmd_unbind *)data;
3153
3154	bzero(cmd_unbind, sizeof(struct vpnctl_cmd_unbind));
3155	cmd_unbind->hdr.len = htons(sizeof(struct vpnctl_cmd_unbind) - sizeof(struct vpnctl_hdr));
3156	cmd_unbind->hdr.msg_type = htons(VPNCTL_CMD_UNBIND);
3157	cmd_unbind->address = address;
3158	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: sending UNBIND to racoon control socket"));
3159	write(fd, cmd_unbind, sizeof(struct vpnctl_cmd_unbind));
3160	return 0;
3161}
3162
3163/* -----------------------------------------------------------------------------
3164----------------------------------------------------------------------------- */
3165int racoon_send_cmd_start_ph2(int fd, u_int32_t address, CFDictionaryRef ipsec_dict)
3166{
3167	u_int8_t	*p;
3168	struct		vpnctl_cmd_start_ph2 *cmd_start_ph2 = NULL;
3169	struct		vpnctl_algo	*algo;
3170	int			policy_count;
3171	u_int16_t	selector_count = 0;
3172	int			nb, i;
3173    char		src_address[32], dst_address[32], str[32];
3174	u_int32_t	remote_address;
3175	CFArrayRef	policies;
3176	CFIndex		start, end;
3177	size_t		bufsiz, msglen;
3178	char		*errstr = '\0';
3179
3180#define NB_ALGOS 6
3181
3182	policy_count = IPSecCountPolicies(ipsec_dict);
3183	if (policy_count <= 0) {
3184		errstr = "cannot create ph2 config - no policies found";
3185		goto fail;
3186	}
3187
3188	/* allocate max space needed - adjust len later */
3189	bufsiz = sizeof(struct vpnctl_cmd_start_ph2) + ((policy_count * sizeof(struct vpnctl_sa_selector)) * 2) + (NB_ALGOS * sizeof(struct vpnctl_algo));
3190	cmd_start_ph2 = malloc(bufsiz);
3191	if (cmd_start_ph2 == NULL) {
3192		errstr = "out of memory";
3193		goto fail;
3194	}
3195
3196	bzero(cmd_start_ph2, bufsiz);
3197	cmd_start_ph2->hdr.msg_type = htons(VPNCTL_CMD_START_PH2);
3198	cmd_start_ph2->address = address;
3199
3200	/* XXX let use default for now */
3201	cmd_start_ph2->lifetime = htonl(3600);
3202	cmd_start_ph2->selector_count = 0;
3203	cmd_start_ph2->algo_count = htons(NB_ALGOS);
3204
3205	if (!GetStrAddrFromDict(ipsec_dict, kRASPropIPSecLocalAddress, src_address, sizeof(src_address))) {
3206		errstr = "incorrect local address";
3207		goto fail;
3208	}
3209
3210	if (!GetStrAddrFromDict(ipsec_dict, kRASPropIPSecRemoteAddress, dst_address, sizeof(dst_address))) {
3211		errstr = "incorrect remote address";
3212		goto fail;
3213	}
3214
3215	if (!inet_aton(dst_address, (struct in_addr *)&remote_address)) {
3216		errstr = "invalid remote address";
3217		goto fail;
3218	}
3219
3220	if (remote_address != address) {
3221		errstr = "remote address mismatch";
3222		goto fail;
3223	}
3224
3225	policies = CFDictionaryGetValue(ipsec_dict, kRASPropIPSecPolicies);
3226	if (!isArray(policies) || (nb = CFArrayGetCount(policies)) == 0) {
3227		errstr = "no policy found";
3228		goto fail;
3229	}
3230
3231	start = 0;
3232	end = nb;
3233
3234	p = ((u_int8_t *)(cmd_start_ph2)) + sizeof(struct vpnctl_cmd_start_ph2);
3235
3236	for (i = start; i < end; i++) {
3237
3238		int				tunnel, in, out;
3239		CFDictionaryRef policy;
3240		CFStringRef		policymode, policydirection, policylevel;
3241		struct			in_addr		local_net_address, remote_net_address;
3242		u_int16_t		local_net_port, remote_net_port;
3243		u_int32_t		local_prefix, remote_prefix, local_mask, remote_mask;
3244		u_int32_t		protocol;
3245		struct			vpnctl_sa_selector *sa;
3246
3247		protocol = 0xFF;
3248
3249		policy = CFArrayGetValueAtIndex(policies, i);
3250		if (!isDictionary(policy)) {
3251			errstr = "incorrect policy found";
3252			goto fail;
3253		}
3254
3255		/* build policies in and out */
3256
3257		tunnel = 1;
3258		policymode = CFDictionaryGetValue(policy, kRASPropIPSecPolicyMode);
3259		if (isString(policymode)) {
3260
3261			if (CFEqual(policymode, kRASValIPSecPolicyModeTunnel))
3262				tunnel = 1;
3263			else if (CFEqual(policymode, kRASValIPSecPolicyModeTransport))
3264				tunnel = 0;
3265			else {
3266				errstr = "incorrect policy type found";
3267				goto fail;
3268			}
3269		}
3270
3271		/* if policy direction is not specified, in/out is assumed */
3272		in = out = 1;
3273		policydirection = CFDictionaryGetValue(policy, kRASPropIPSecPolicyDirection);
3274		if (isString(policydirection)) {
3275
3276			if (CFEqual(policydirection, kRASValIPSecPolicyDirectionIn))
3277				out = 0;
3278			else if (CFEqual(policydirection, kRASValIPSecPolicyDirectionOut))
3279				in = 0;
3280			else if (!CFEqual(policydirection, kRASValIPSecPolicyDirectionInOut)) {
3281				errstr = "incorrect policy direction found";
3282				goto fail;
3283			}
3284		}
3285
3286		policylevel = CFDictionaryGetValue(policy, kRASPropIPSecPolicyLevel);
3287		if (!isString(policylevel) ||
3288			(!CFEqual(policylevel, kRASValIPSecPolicyLevelUnique) && !CFEqual(policylevel, kRASValIPSecPolicyLevelRequire)))
3289			continue;
3290
3291		if (tunnel) {
3292
3293			int j;
3294
3295			/* get local and remote networks */
3296
3297			if (!GetStrAddrFromDict(policy, kRASPropIPSecPolicyLocalAddress, str, sizeof(str))) {
3298				errstr = "incorrect local network";
3299				goto fail;
3300			}
3301
3302			local_net_port = htons(0);
3303			if (!inet_aton(str, &local_net_address)) {
3304				errstr = "incorrect local network";
3305				goto fail;
3306			}
3307
3308			GetIntFromDict(policy, kRASPropIPSecPolicyLocalPrefix, &local_prefix, 32);
3309			for (j = 0, local_mask = 0; j < local_prefix; j++)
3310				local_mask = (local_mask >> 1) | 0x80000000;
3311
3312			if (!GetStrAddrFromDict(policy, kRASPropIPSecPolicyRemoteAddress, str, sizeof(str))) {
3313				errstr = "incorrect remote network";
3314				goto fail;
3315			}
3316
3317			remote_net_port = htons(0);
3318			if (!inet_aton(str, &remote_net_address)) {
3319				errstr = "incorrect remote network";
3320				goto fail;
3321			}
3322
3323			GetIntFromDict(policy, kRASPropIPSecPolicyRemotePrefix, &remote_prefix, 32);
3324			for (j = 0, remote_mask = 0; j < remote_prefix; j++)
3325				remote_mask = (remote_mask >> 1) | 0x80000000;
3326
3327		}
3328		else {
3329			u_int32_t val;
3330
3331			GetIntFromDict(policy, kRASPropIPSecPolicyLocalPort, &val, 0);
3332			local_net_port = htons(val);
3333			if (!inet_aton(src_address, &local_net_address)) {
3334				errstr = "incorrect local address";
3335				goto fail;
3336			}
3337
3338			local_mask = local_net_address.s_addr ? 0xFFFFFFFF : 0;
3339
3340			GetIntFromDict(policy, kRASPropIPSecPolicyRemotePort, &val, 0);
3341			remote_net_port = htons(val);
3342			if (!inet_aton(dst_address, &remote_net_address)) {
3343				errstr = "incorrect remote address";
3344				goto fail;
3345			}
3346
3347			remote_mask = remote_net_address.s_addr ? 0xFFFFFFFF : 0;
3348
3349			GetIntFromDict(policy, kRASPropIPSecPolicyProtocol, &protocol, 0);
3350
3351		}
3352
3353		/* setup phase2 command */
3354
3355		if (out) {
3356			sa = ALIGNED_CAST(struct vpnctl_sa_selector *)p;
3357			sa->src_tunnel_address = local_net_address.s_addr;
3358			sa->src_tunnel_mask = htonl(local_mask);
3359			sa->src_tunnel_port = local_net_port;
3360			sa->dst_tunnel_address = remote_net_address.s_addr;
3361			sa->dst_tunnel_mask = htonl(remote_mask);
3362			sa->dst_tunnel_port = remote_net_port;
3363			sa->ul_protocol = htons((u_int16_t)protocol);
3364			selector_count++;
3365			p += sizeof(struct vpnctl_sa_selector);
3366		}
3367
3368		if (in) {
3369			sa = ALIGNED_CAST(struct vpnctl_sa_selector *)p;
3370			sa->dst_tunnel_address = local_net_address.s_addr;
3371			sa->dst_tunnel_mask = htonl(local_mask);
3372			sa->dst_tunnel_port = local_net_port;
3373			sa->src_tunnel_address = remote_net_address.s_addr;
3374			sa->src_tunnel_mask = htonl(remote_mask);
3375			sa->src_tunnel_port = remote_net_port;
3376			sa->ul_protocol = htons((u_int16_t)protocol);
3377			selector_count++;
3378			p += sizeof(struct vpnctl_sa_selector);
3379		}
3380	}
3381	cmd_start_ph2->selector_count = htons(selector_count);
3382
3383	algo = ALIGNED_CAST(struct vpnctl_algo *)p;
3384	algo->algo_class = htons(algclass_ipsec_enc);
3385	algo->algo = htons(algtype_aes);
3386	algo->key_len = htons(256);
3387
3388	p += sizeof(struct vpnctl_algo);
3389	algo = ALIGNED_CAST(struct vpnctl_algo *)p;
3390	algo->algo_class = htons(algclass_ipsec_enc);
3391	algo->algo = htons(algtype_aes);
3392	algo->key_len = htons(0);
3393
3394	p += sizeof(struct vpnctl_algo);
3395	algo = ALIGNED_CAST(struct vpnctl_algo *)p;
3396	algo->algo_class = htons(algclass_ipsec_enc);
3397	algo->algo = htons(algtype_3des);
3398	algo->key_len = htons(0);
3399
3400	p += sizeof(struct vpnctl_algo);
3401	algo = ALIGNED_CAST(struct vpnctl_algo *)p;
3402	algo->algo_class = htons(algclass_ipsec_auth);
3403	algo->algo = htons(algtype_hmac_sha1);
3404	algo->key_len = htons(0);
3405
3406	p += sizeof(struct vpnctl_algo);
3407	algo = ALIGNED_CAST(struct vpnctl_algo *)p;
3408	algo->algo_class = htons(algclass_ipsec_auth);
3409	algo->algo = htons(algtype_hmac_md5);
3410	algo->key_len = htons(0);
3411
3412	p += sizeof(struct vpnctl_algo);
3413	algo = ALIGNED_CAST(struct vpnctl_algo *)p;
3414	algo->algo_class = htons(algclass_ipsec_comp);
3415	algo->algo = htons(algtype_deflate);
3416	algo->key_len = htons(0);
3417
3418	msglen = sizeof(struct vpnctl_cmd_start_ph2) +
3419					(selector_count * sizeof(struct vpnctl_sa_selector)) +
3420					(NB_ALGOS * sizeof(struct vpnctl_algo));
3421	cmd_start_ph2->hdr.len = htons(msglen - sizeof(struct vpnctl_hdr));
3422
3423	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: sending START_PH2 to racoon control socket"));
3424	write(fd, cmd_start_ph2, msglen);
3425	IPSECLOGASLMSG("IPSec Phase2 starting.\n");
3426
3427	free(cmd_start_ph2);
3428	return 0;
3429
3430fail:
3431	ipsec_log(LOG_ERR, CFSTR("IPSec Controller: failed to start phase2 - '%s'"), errstr);
3432	if (cmd_start_ph2)
3433		free(cmd_start_ph2);
3434	return -1;
3435}
3436
3437/* -----------------------------------------------------------------------------
3438 ----------------------------------------------------------------------------- */
3439int racoon_send_cmd_assert (struct service *serv)
3440{
3441	struct vpnctl_cmd_assert msg;
3442	CFRunLoopTimerContext    context = { 0, serv, NULL, NULL, NULL };
3443
3444	bzero(&msg, sizeof(msg));
3445	msg.hdr.msg_type = htons(VPNCTL_CMD_ASSERT);
3446	msg.src_address = serv->u.ipsec.our_address.sin_addr.s_addr;
3447	msg.dst_address = serv->u.ipsec.peer_address.sin_addr.s_addr;
3448	msg.hdr.len = htons(sizeof(msg) - sizeof(msg.hdr));;
3449
3450	write(serv->u.ipsec.controlfd, &msg, sizeof(msg));
3451	serv->u.ipsec.ping_count = 0;
3452
3453	IPSEC_ASSERT_IDLE(serv->u.ipsec);
3454	if (!serv->u.ipsec.timerref) {
3455		serv->u.ipsec.timerref = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + TIMEOUT_ASSERT_IDLE, FAR_FUTURE, 0, 0, racoon_timer, &context);
3456		if (!serv->u.ipsec.timerref) {
3457			ipsec_log(LOG_ERR, CFSTR("IPSec Controller: assert cannot create RunLoop timer"));
3458			goto fail;
3459		}
3460		CFRunLoopAddTimer(CFRunLoopGetCurrent(), serv->u.ipsec.timerref, kCFRunLoopCommonModes);
3461	} else {
3462		CFRunLoopTimerSetNextFireDate(serv->u.ipsec.timerref, CFAbsoluteTimeGetCurrent() + TIMEOUT_ASSERT_IDLE);
3463	}
3464	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: wait for %d secs before forcing SAs to rekey"), TIMEOUT_ASSERT_IDLE);
3465	return 0;
3466
3467fail:
3468	if (serv->u.ipsec.laststatus == IPSEC_NO_ERROR)
3469		serv->u.ipsec.laststatus = IPSEC_GENERIC_ERROR;
3470	ipsec_log(LOG_ERR, CFSTR("IPSec Controller: ASSERT failed"));
3471	ipsec_stop(serv, 0);
3472	return -1;
3473}
3474
3475/* -----------------------------------------------------------------------------
3476----------------------------------------------------------------------------- */
3477
3478static
3479int racoon_restart(struct service *serv, struct sockaddr_in *address)
3480{
3481	char			*errorstr;
3482	int				error, need_kick = 0, found;
3483	CFStringRef		string;
3484    CFRunLoopTimerContext	context = { 0, serv, NULL, NULL, NULL };
3485	CFDictionaryRef userdict = 0;
3486	Boolean			using_temp_xauth_name = FALSE;
3487	CFTypeRef		value;
3488
3489	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: racoon_restart..."));
3490
3491	/* unconfigure ipsec first */
3492	if (serv->u.ipsec.policies_installed) {
3493		error = IPSecRemovePolicies(serv->u.ipsec.config, -1, &errorstr);
3494		if (error)
3495			ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Cannot remove policies, error '%s'"), errorstr);
3496
3497		IPSecRemoveSecurityAssociations((struct sockaddr *)&serv->u.ipsec.our_address, (struct sockaddr *)&serv->u.ipsec.peer_address);
3498		serv->u.ipsec.policies_installed = 0;
3499	}
3500	if (serv->ne_sm_bridge != NULL) {
3501		ne_sm_bridge_request_uninstall(serv->ne_sm_bridge);
3502	}
3503	uninstall_mode_config(serv, TRUE);
3504
3505	if (serv->u.ipsec.config_applied) {
3506		// just remove the file, as will kill kick racoon with the config of the load balancing adress
3507		// this is to avoid useless sighup of racoon
3508		error = IPSecRemoveConfigurationFile(serv->u.ipsec.config, &errorstr);
3509		if (error)
3510			ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Cannot remove configuration, error '%s'"), errorstr);
3511		serv->u.ipsec.config_applied = 0;
3512		need_kick = 1;
3513	}
3514
3515	serv->u.ipsec.ping_count = 0;
3516
3517	CLEAR_VPN_PORTMAPPING(serv);
3518
3519	/* then try new address */
3520	bcopy(address, &serv->u.ipsec.peer_address, sizeof(serv->u.ipsec.peer_address));
3521
3522	bool useBoundInterface = FALSE;
3523	if (serv->connectopts) {
3524		if (GetStrFromDict(serv->connectopts, CFSTR(NESessionStartOptionOutgoingInterface), serv->u.ipsec.lower_interface, sizeof(serv->u.ipsec.lower_interface), "")) {
3525			useBoundInterface = TRUE;
3526		}
3527	}
3528
3529	if (get_src_address((struct sockaddr *)&serv->u.ipsec.our_address, (struct sockaddr *)&serv->u.ipsec.peer_address, useBoundInterface ? serv->u.ipsec.lower_interface : NULL, NULL)) {
3530		serv->u.ipsec.laststatus = IPSEC_NOLOCALNETWORK_ERROR;
3531		ipsec_log(LOG_ERR, CFSTR("IPSec Controller: cannot get our local address..."));
3532		goto fail;
3533	}
3534
3535	if (!useBoundInterface) {
3536		copyGateway(gDynamicStore, AF_INET,
3537			serv->u.ipsec.lower_interface, sizeof(serv->u.ipsec.lower_interface),
3538			(struct sockaddr *)&serv->u.ipsec.lower_gateway, sizeof(serv->u.ipsec.lower_gateway));
3539	}
3540
3541#if !TARGET_OS_EMBEDDED
3542    serv->u.ipsec.lower_interface_media = get_if_media(serv->u.ipsec.lower_interface);
3543    serv->u.ipsec.timeout_lower_interface_change = get_interface_timeout(serv->u.ipsec.lower_interface_media);
3544#else
3545	serv->u.ipsec.lower_interface_media = 0;
3546    serv->u.ipsec.timeout_lower_interface_change = get_interface_timeout(0);
3547#endif /* !iPhone */
3548
3549	// check to see if interface is captive: if so, bail if the interface is not ready.
3550	if (check_interface_captive_and_not_ready(gDynamicStore, serv->u.ipsec.lower_interface)) {
3551		// TODO: perhaps we should wait for a few seconds?
3552		goto fail;
3553	}
3554
3555	TRACK_VPN_LOCATION(serv);
3556
3557	/* if retry, then change src/dst address, otherwise create the config */
3558	if (!serv->u.ipsec.config) {
3559
3560		CFStringRef auth_method;
3561		auth_method = CFDictionaryGetValue(serv->systemprefs, kRASPropIPSecAuthenticationMethod);
3562		if (!isString(auth_method) || CFEqual(auth_method, kRASValIPSecAuthenticationMethodSharedSecret)) {
3563			auth_method = kRASValIPSecAuthenticationMethodSharedSecret;
3564
3565		}
3566		else if (CFEqual(auth_method, kRASValIPSecAuthenticationMethodCertificate)) {
3567			serv->flags |= FLAG_USECERTIFICATE;
3568#if 0
3569			/* need to check for share secret at some point in the path */
3570			certificate = CFDictionaryGetValue(useripsec_dict, kRASPropIPSecLocalCertificate);
3571			if (!isData(certificate)) {
3572				devstatus = EXIT_L2TP_NOCERTIFICATE;
3573				error("L2TP: no user certificate  found.\n");
3574				goto fail;
3575			}
3576#endif
3577		}
3578
3579		CFStringRef verify_id;
3580		verify_id = CFDictionaryGetValue(serv->systemprefs, kRASPropIPSecIdentifierVerification);
3581		if (verify_id && !isString(verify_id)) {
3582#if 0
3583			/* need to check correct value */
3584			error("L2TP: incorrect identifier verification found.\n");
3585			goto fail;
3586#endif
3587		}
3588
3589
3590		/* now create the default config */
3591		CFStringRef remote_address = CFDictionaryGetValue(serv->systemprefs, kRASPropIPSecRemoteAddress);
3592
3593		serv->u.ipsec.config = IPSecCreateCiscoDefaultConfiguration(&serv->u.ipsec.our_address,
3594			&serv->u.ipsec.peer_address, cfstring_is_ip(remote_address) ? NULL : remote_address, auth_method,
3595			1, 0, verify_id);
3596		if (!serv->u.ipsec.config) {
3597			ipsec_log(LOG_ERR, CFSTR("IPSec Controller: cannot create IPSec dictionary..."));
3598			goto fail;
3599		}
3600
3601		/* merge the system config prefs into the default dictionary */
3602		CFDictionaryApplyFunction(serv->systemprefs, merge_ipsec_dict, serv->u.ipsec.config);
3603
3604		if (useBoundInterface) {
3605			CFDictionarySetValue(serv->u.ipsec.config, kRASPropIPSecForceLocalAddress, kCFBooleanTrue);
3606		}
3607
3608		// by default, want to configure idle time out when connecting OnDemand
3609		if (serv->flags & FLAG_ONDEMAND) {
3610			CFNumberRef num;
3611			int val;
3612
3613			val = 1;
3614			if ((num = CFNumberCreate(NULL, kCFNumberIntType, &val))) {
3615				CFDictionarySetValue(serv->u.ipsec.config, kRASPropIPSecDisconnectOnIdle, num);
3616				CFRelease(num);
3617			}
3618			val = 120; // 2 minutes by default
3619			if ((num = CFNumberCreate(NULL, kCFNumberIntType, &val))) {
3620				CFDictionarySetValue(serv->u.ipsec.config, kRASPropIPSecDisconnectOnIdleTimer, num);
3621				CFRelease(num);
3622			}
3623		}
3624
3625		if (serv->connectopts && (userdict = CFDictionaryGetValue(serv->connectopts, kSCEntNetIPSec))) {
3626
3627			value = CFDictionaryGetValue(userdict, kRASPropIPSecXAuthName);
3628			if (isString(value))
3629				CFDictionarySetValue(serv->u.ipsec.config, kRASPropIPSecXAuthName, value);
3630
3631			value = CFDictionaryGetValue(userdict, kRASPropIPSecXAuthPassword);
3632			if (isString(value))
3633				CFDictionarySetValue(serv->u.ipsec.config, kRASPropIPSecXAuthPassword, value);
3634		}
3635
3636
3637		/* Change to Hybrid authentication if applicable */
3638		#define IPSecLocalIdentifierHybridSuffix	CFSTR("[hybrid]")
3639		value = CFDictionaryGetValue(serv->u.ipsec.config, kRASPropIPSecLocalIdentifier);
3640		if (isString(value) && CFStringHasSuffix(value, IPSecLocalIdentifierHybridSuffix)) {
3641			CFStringRef value1 = CFStringCreateWithSubstring(NULL, value, CFRangeMake(0, CFStringGetLength(value) - CFStringGetLength(IPSecLocalIdentifierHybridSuffix)));
3642			if (value1) {
3643				CFDictionarySetValue(serv->u.ipsec.config, kRASPropIPSecLocalIdentifier, value1);
3644				CFDictionarySetValue(serv->u.ipsec.config, kRASPropIPSecAuthenticationMethod, kRASValIPSecAuthenticationMethodHybrid);
3645				CFRelease(value1);
3646				CFDictionarySetValue(serv->u.ipsec.config, kRASPropIPSecRemoteIdentifier, remote_address);
3647				CFDictionarySetValue(serv->u.ipsec.config, kRASPropIPSecIdentifierVerification, kRASValIPSecIdentifierVerificationUseRemoteIdentifier);
3648			}
3649		}
3650
3651		/* Complete shared secret, with defaut convention "serviceID.SS" if necessary */
3652		if (CFEqual(auth_method, kRASValIPSecAuthenticationMethodSharedSecret)) {
3653
3654			found = 0;
3655			/* first check is secret is available in the prefs */
3656			CFStringRef secret_string = CFDictionaryGetValue(serv->u.ipsec.config, kRASPropIPSecSharedSecret);
3657			if (isString(secret_string)) {
3658				/* secret or secret keychain is in the prefs, leave it alone */
3659				found = 1;
3660			}
3661			else {
3662				/* encryption is not specified, and secret was missing. check connect options */
3663				if (serv->connectopts && userdict != NULL) {
3664					CFStringRef secret_string = CFDictionaryGetValue(userdict, kRASPropIPSecSharedSecret);
3665					if (isString(secret_string)) {
3666						found = 1;
3667						CFDictionarySetValue(serv->u.ipsec.config, kRASPropIPSecSharedSecret, secret_string);
3668						CFDictionaryRemoveValue(serv->u.ipsec.config, kRASPropIPSecSharedSecretEncryption);
3669					}
3670				}
3671				else {
3672					/* secret is not in the prefs, check for encryption pref */
3673					CFStringRef secret_encryption_string = CFDictionaryGetValue(serv->u.ipsec.config, kRASPropIPSecSharedSecretEncryption);
3674					if (my_CFEqual(secret_encryption_string, kRASValIPSecSharedSecretEncryptionKeychain)) {
3675						/* encryption is KeyChain. Create a default secret key for the key chain */
3676						secret_string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@.SS"), serv->serviceID);
3677						if (secret_string) {
3678							found = 1;
3679							CFDictionarySetValue(serv->u.ipsec.config, kRASPropIPSecSharedSecret, secret_string);
3680							CFRelease(secret_string);
3681						}
3682					}
3683				}
3684			}
3685
3686			if (!found) {
3687				serv->u.ipsec.laststatus = IPSEC_NOSHAREDSECRET_ERROR;
3688				ipsec_log(LOG_ERR, CFSTR("IPSec Controller: incorrect shared secret found."));
3689				goto fail;
3690			}
3691
3692		}
3693	}
3694	else {
3695		string = CFStringCreateWithCString(0, addr2ascii(AF_INET, &serv->u.ipsec.our_address.sin_addr, sizeof(serv->u.ipsec.our_address.sin_addr), 0), kCFStringEncodingASCII);
3696		if (string) {
3697			CFDictionarySetValue(serv->u.ipsec.config, kRASPropIPSecLocalAddress, string);
3698			CFRelease(string);
3699		}
3700		string = CFStringCreateWithCString(0, addr2ascii(AF_INET, &serv->u.ipsec.peer_address.sin_addr, sizeof(serv->u.ipsec.peer_address.sin_addr), 0), kCFStringEncodingASCII);
3701		if (string) {
3702			CFDictionarySetValue(serv->u.ipsec.config, kRASPropIPSecRemoteAddress, string);
3703			CFRelease(string);
3704		}
3705		if (useBoundInterface) {
3706			CFDictionarySetValue(serv->u.ipsec.config, kRASPropIPSecForceLocalAddress, kCFBooleanTrue);
3707		}
3708	}
3709
3710	ipsec_log(LOG_DEBUG, CFSTR("IPSec Controller: Complete IPsec dictionary %@"), serv->u.ipsec.config);
3711
3712	/* Temporarily add in XAuthName if missing when creating the racoon conf file */
3713	if (!CFDictionaryContainsKey(serv->u.ipsec.config, kRASPropIPSecXAuthName)) {
3714		CFDictionarySetValue(serv->u.ipsec.config, kRASPropIPSecXAuthName, CFSTR(" "));
3715		using_temp_xauth_name = TRUE;
3716	}
3717	error = IPSecApplyConfiguration(serv->u.ipsec.config, &errorstr);
3718	if (using_temp_xauth_name) {
3719		CFDictionaryRemoveValue(serv->u.ipsec.config, kRASPropIPSecXAuthName);
3720	}
3721	if (error) {
3722		ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Cannot apply configuration, error '%s'"), errorstr);
3723		serv->u.ipsec.laststatus = IPSEC_CONFIGURATION_ERROR;
3724		goto fail;
3725	}
3726
3727	serv->u.ipsec.config_applied = 1;
3728	need_kick = 0;
3729
3730	/* Install policies and trigger racoon */
3731	if (IPSecCountPolicies(serv->u.ipsec.config)) {
3732		error = IPSecInstallPolicies(serv->u.ipsec.config, -1, &errorstr);
3733		if (error) {
3734			ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Cannot install policies, error '%s'"), errorstr);
3735			serv->u.ipsec.laststatus = IPSEC_CONFIGURATION_ERROR;
3736			goto fail;
3737		}
3738
3739		serv->u.ipsec.policies_installed = 1;
3740	}
3741
3742	/* open and connect to the racoon control socket */
3743	if (serv->u.ipsec.controlfd == -1) {
3744		if (racoon_create_socket(serv) < 0) {
3745			ipsec_log(LOG_ERR, CFSTR("IPSec Controller: cannot create racoon control socket"));
3746			serv->u.ipsec.laststatus = IPSEC_RACOONCONTROL_ERROR;
3747			goto fail;
3748		}
3749	}
3750	else {
3751		racoon_send_cmd_unbind(serv->u.ipsec.controlfd, htonl(0xFFFFFFFF));
3752	}
3753
3754	SET_VPN_PORTMAPPING(serv);
3755
3756	racoon_send_cmd_bind(serv->u.ipsec.controlfd, serv->u.ipsec.peer_address.sin_addr.s_addr, gIPSecAppVersion);
3757	racoon_send_cmd_connect(serv->u.ipsec.controlfd, serv->u.ipsec.peer_address.sin_addr.s_addr);
3758
3759	if (!serv->u.ipsec.timerref) {
3760		serv->u.ipsec.timerref = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + TIMEOUT_INITIAL_CONTACT, FAR_FUTURE, 0, 0, racoon_timer, &context);
3761		if (!serv->u.ipsec.timerref) {
3762			ipsec_log(LOG_ERR, CFSTR("IPSec Controller: cannot create RunLoop timer"));
3763			goto fail;
3764		}
3765		CFRunLoopAddTimer(CFRunLoopGetCurrent(), serv->u.ipsec.timerref, kCFRunLoopCommonModes);
3766	}
3767	else {
3768		CFRunLoopTimerSetNextFireDate(serv->u.ipsec.timerref, CFAbsoluteTimeGetCurrent() + TIMEOUT_INITIAL_CONTACT);
3769	}
3770	return 0;
3771
3772fail:
3773	if (serv->u.ipsec.laststatus == IPSEC_NO_ERROR)
3774		serv->u.ipsec.laststatus = IPSEC_GENERIC_ERROR;
3775	ipsec_log(LOG_ERR, CFSTR("IPSec Controller: restart failed"));
3776	if (need_kick)
3777		IPSecKickConfiguration();
3778	ipsec_stop(serv, 0);
3779    return serv->u.ipsec.laststatus;
3780}
3781
3782
3783#if TARGET_OS_EMBEDDED
3784/* -----------------------------------------------------------------------------
3785 ----------------------------------------------------------------------------- */
3786void ipsec_cellular_event(struct service *serv, int event)
3787{
3788	switch (event) {
3789		case CELLULAR_BRINGUP_SUCCESS_EVENT:
3790			racoon_resolve(serv);
3791			break;
3792		case CELLULAR_BRINGUP_FATAL_FAILURE_EVENT:
3793		case CELLULAR_BRINGUP_NETWORK_FAILURE_EVENT:
3794			serv->u.ipsec.laststatus = IPSEC_EDGE_ACTIVATION_ERROR;
3795			ipsec_stop(serv, 0);
3796			break;
3797	}
3798}
3799#endif
3800
3801/* -----------------------------------------------------------------------------
3802 ----------------------------------------------------------------------------- */
3803int racoon_resolve(struct service *serv)
3804{
3805	char			remoteaddress[255];
3806
3807	GetStrFromDict (serv->systemprefs, kRASPropIPSecRemoteAddress, remoteaddress, sizeof(remoteaddress), "");
3808
3809	serv->u.ipsec.peer_address.sin_len = sizeof(serv->u.ipsec.peer_address);
3810	serv->u.ipsec.peer_address.sin_family = AF_INET;
3811	serv->u.ipsec.peer_address.sin_port = htons(0);
3812	if (!inet_aton(remoteaddress, &serv->u.ipsec.peer_address.sin_addr)) {
3813		if (dns_start_query(serv, remoteaddress)) {
3814			serv->u.ipsec.laststatus = IPSEC_RESOLVEADDRESS_ERROR;
3815			goto fail;
3816		}
3817		return 0;
3818	}
3819
3820	return racoon_restart(serv, &serv->u.ipsec.peer_address);
3821
3822fail:
3823	if (serv->u.ipsec.laststatus == IPSEC_NO_ERROR)
3824		serv->u.ipsec.laststatus = IPSEC_GENERIC_ERROR;
3825
3826	ipsec_stop(serv, 0);
3827    return serv->u.ipsec.laststatus;
3828}
3829
3830/* -----------------------------------------------------------------------------
3831 ----------------------------------------------------------------------------- */
3832int ipsec_start(struct service *serv, CFDictionaryRef options, uid_t uid, gid_t gid, mach_port_t bootstrap, u_int8_t onTraffic, u_int8_t onDemand)
3833{
3834	char			remoteaddress[255];
3835
3836	if (serv->initialized == FALSE) {
3837		serv->u.ipsec.laststatus = IPSEC_CONFIGURATION_ERROR;
3838		display_notification(serv, NULL, serv->u.ipsec.laststatus, dialog_default_type);
3839		return serv->u.ipsec.laststatus;
3840	}
3841
3842	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: ipsec_start, ondemand flag = %d"), onDemand);
3843
3844    switch (serv->u.ipsec.phase) {
3845        case IPSEC_IDLE:
3846            break;
3847
3848        default:
3849			if (my_CFEqual(options, serv->connectopts)) {
3850				// notify client, so at least then can get the status if they were waiting got it
3851				phase_changed(serv, serv->u.ipsec.phase);
3852				return 0;
3853			}
3854            return EIO;	// not the right time to dial
3855    }
3856
3857	/* check for pending cert invalid alert */
3858	if (serv->userNotificationRef) {
3859		if ( onDemand ){
3860			if (IPSEC_STATUS_IS_CLIENT_CERTIFICATE_INVALID(serv->u.ipsec.laststatus)){
3861				ipsec_log(LOG_ERR, CFSTR("IPSec Controller: ipsec_start fails cert validity, returns error %d "), serv->u.ipsec.laststatus);
3862				return serv->u.ipsec.laststatus;
3863			}
3864		}
3865		CFUserNotificationCancel(serv->userNotificationRef);
3866		CFRunLoopRemoveSource(CFRunLoopGetCurrent(), serv->userNotificationRLS, kCFRunLoopDefaultMode);
3867		my_CFRelease(&serv->userNotificationRef);
3868		my_CFRelease(&serv->userNotificationRLS);
3869	}
3870
3871	ipsec_updatephase(serv, IPSEC_INITIALIZE);
3872	IPSEC_UNASSERT(serv->u.ipsec);
3873	serv->was_running = 0;
3874	service_started(serv);
3875    serv->u.ipsec.laststatus = IPSEC_NO_ERROR;
3876	serv->u.ipsec.resolvedAddress      = 0;
3877	serv->u.ipsec.resolvedAddressError = NETDB_SUCCESS;
3878	serv->u.ipsec.next_address = 0;
3879	serv->u.ipsec.ping_count = 0;
3880	serv->u.ipsec.awaiting_peer_resp = 0;
3881
3882	serv->connectopts = options;
3883    my_CFRetain(serv->connectopts);
3884
3885    serv->uid = uid;
3886    serv->gid = gid;
3887
3888    scnc_bootstrap_retain(serv, bootstrap);
3889
3890    if (onDemand)
3891        serv->flags |= FLAG_ONDEMAND;
3892	else
3893		serv->flags &= ~FLAG_ONDEMAND;
3894	serv->flags &= ~FLAG_USECERTIFICATE;
3895
3896	ipsec_log(LOG_DEBUG, CFSTR("IPSec Controller: IPSec System Prefs %@"), serv->systemprefs);
3897
3898#if DEBUG /* connectopts can contain cleartext passwords */
3899	ipsec_log(LOG_DEBUG, CFSTR("IPSec Controller: IPSec User Options %@"), serv->connectopts);
3900#endif
3901
3902	/* build the peer address */
3903	if (!GetStrFromDict (serv->systemprefs, kRASPropIPSecRemoteAddress, remoteaddress, sizeof(remoteaddress), "")) {
3904		serv->u.ipsec.laststatus = IPSEC_NOSERVERADDRESS_ERROR;
3905		ipsec_log(LOG_ERR, CFSTR("IPSec Controller: cannot find RemoteAddress ..."));
3906		goto fail;
3907	}
3908	if (!racoon_validate_cfg_str(remoteaddress)) {
3909		serv->u.ipsec.laststatus = IPSEC_NOSERVERADDRESS_ERROR;
3910		ipsec_log(LOG_ERR, CFSTR("IPSec Controller: invalid RemoteAddress ..."));
3911		goto fail;
3912	}
3913
3914	IPSECLOGASLMSG("IPSec connecting to server %s\n", remoteaddress);
3915
3916	{
3917		serv->u.ipsec.xauth_flags = XAUTH_FIRST_TIME;
3918		// force prompt if necessary
3919		CFStringRef encryption = CFDictionaryGetValue(serv->systemprefs, kSCPropNetIPSecXAuthPasswordEncryption);
3920		if (isString(encryption)
3921			&& CFStringCompare(encryption, kSCValNetIPSecXAuthPasswordEncryptionPrompt, 0) == kCFCompareEqualTo) {
3922			serv->u.ipsec.xauth_flags |= XAUTH_MUST_PROMPT;
3923		}
3924	}
3925
3926	if (serv->ne_sm_bridge == NULL) {
3927		/* open the kernel event socket */
3928		if (serv->u.ipsec.eventfd == -1) {
3929			if (event_create_socket(serv, &serv->u.ipsec.eventfd, &serv->u.ipsec.eventref, event_callback, FALSE) < 0) {
3930				ipsec_log(LOG_ERR, CFSTR("IPSec Controller: cannot create event socket"));
3931				goto fail;
3932			}
3933		}
3934	}
3935
3936#if TARGET_OS_EMBEDDED
3937	{
3938		/* first, bring up Cellular */
3939		int need_cellular = FALSE;
3940		SCNetworkReachabilityRef ref = NULL;
3941		SCNetworkConnectionFlags	flags = 0;
3942		struct sockaddr_in peer_address;	/* the other side IP address */
3943
3944		// we don't want a synchronous dns request to happen.
3945		// checking for default route is enough
3946		bzero(&peer_address, sizeof(peer_address));
3947		peer_address.sin_len = sizeof(peer_address);
3948		peer_address.sin_family = AF_INET;
3949		ref = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&peer_address);
3950		//ref = SCNetworkReachabilityCreateWithName(NULL, remoteaddress);
3951		if (ref) {
3952
3953			if (SCNetworkReachabilityGetFlags(ref, &flags)) {
3954				if ((flags & kSCNetworkReachabilityFlagsReachable) &&
3955					(flags & kSCNetworkReachabilityFlagsConnectionRequired) &&
3956					(flags & kSCNetworkReachabilityFlagsIsWWAN)) {
3957					need_cellular = TRUE;
3958				}
3959
3960				ipsec_log(LOG_INFO, CFSTR("IPSec Controller: ipsec_start reachability flags = 0x%x, need_cellular = %d"), flags, need_cellular);
3961			}
3962			CFRelease(ref);
3963		}
3964
3965		int enabled = 1;
3966		CFNumberRef numref = CFDictionaryGetValue(serv->systemprefs, kRASPropIPSecNattKeepAliveEnabled);
3967		numref = isA_CFNumber(numref);
3968		if (numref)
3969			CFNumberGetValue(numref, kCFNumberIntType, &enabled);
3970
3971		if (enabled) {
3972			int timer = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? 0 : 60;
3973
3974			numref = CFDictionaryGetValue(serv->systemprefs, kRASPropIPSecNattKeepAliveTimer);
3975			numref = isA_CFNumber(numref);
3976			if (numref)
3977				CFNumberGetValue(numref, kCFNumberIntType, &timer);
3978
3979			size_t oldlen = sizeof(gNattKeepAliveInterval);
3980			sysctlbyname("net.key.natt_keepalive_interval", &gNattKeepAliveInterval, &oldlen, &timer, sizeof(int));
3981		}
3982
3983		if (need_cellular) {
3984			if (!bringup_cellular(serv)) {
3985				// cannot bring cellular up
3986				serv->u.ipsec.laststatus = IPSEC_EDGE_ACTIVATION_ERROR;
3987				goto fail;
3988			}
3989
3990			// cellular connection in progress
3991			return 0;
3992		}
3993	}
3994#endif
3995
3996	return racoon_resolve(serv);
3997
3998fail:
3999	if (serv->u.ipsec.laststatus == IPSEC_NO_ERROR)
4000		serv->u.ipsec.laststatus = IPSEC_GENERIC_ERROR;
4001	ipsec_log(LOG_ERR, CFSTR("IPSec Controller: ipsec_start failed"));
4002	ipsec_stop(serv, 0);
4003    return serv->u.ipsec.laststatus;
4004}
4005
4006// XXX
4007int ipsec_getstatus_hack_notify(struct service *serv)
4008{
4009	SCNetworkConnectionStatus	status = PPP_IDLE;
4010
4011	switch (serv->u.ipsec.phase) {
4012		case IPSEC_INITIALIZE:
4013		case IPSEC_CONTACT:
4014		case IPSEC_PHASE1:
4015		case IPSEC_PHASE1AUTH:
4016		case IPSEC_PHASE2:
4017			status = PPP_ESTABLISH;
4018			break;
4019		case IPSEC_TERMINATE:
4020			status = PPP_TERMINATE;
4021			break;
4022		case IPSEC_RUNNING:
4023			status = PPP_RUNNING;
4024			break;
4025		case IPSEC_IDLE:
4026		default:
4027			status = PPP_IDLE;
4028	}
4029	return status;
4030}
4031
4032/* -----------------------------------------------------------------------------
4033phase change for this config occured
4034----------------------------------------------------------------------------- */
4035static
4036void ipsec_updatephase(struct service *serv, int phase)
4037{
4038
4039    /* check for new state */
4040    if (phase == serv->u.ipsec.phase)
4041        return;
4042
4043    serv->u.ipsec.phase = phase;
4044
4045	phase_changed(serv, phase);
4046	publish_dictnumentry(gDynamicStore, serv->serviceID, kSCEntNetIPSec, kSCPropNetIPSecStatus, phase);
4047}
4048
4049/* -----------------------------------------------------------------------------
4050 detects disconnects caused by recoverable errors and flags the connection for
4051 auto reconnect (i.e. persistence) and avoid UI dialog
4052 ----------------------------------------------------------------------------- */
4053static void
4054ipsec_check_for_disconnect_by_recoverable_error (struct service *serv, u_int32_t *flags)
4055{
4056#if !TARGET_OS_EMBEDDED
4057	if (serv->was_running &&
4058		!serv->persist_connect &&
4059		(serv->flags & (FLAG_FREE | FLAG_ONTRAFFIC | FLAG_ONDEMAND | FLAG_CONNECT | FLAG_SETUP_PERSISTCONNECTION)) == FLAG_SETUP_PERSISTCONNECTION &&
4060		(serv->connecttime && serv->establishtime) &&
4061		serv->u.ipsec.laststatus && serv->u.ipsec.laststatus != IPSEC_PEERDISCONNECT_ERROR) {
4062		ipsec_log(LOG_ERR, CFSTR("IPSec Controller: %d disconnected with status %d. Will try reconnect shortly."),
4063			  serv->u.ipsec.phase, serv->u.ipsec.laststatus);
4064		// prevent error dialog from popping up during this disconnect
4065		*flags = (serv->flags | FLAG_ALERTERRORS);
4066		serv->flags &= ~FLAG_ALERTERRORS;
4067		serv->persist_connect = 1;
4068	}
4069#endif
4070}
4071
4072static int
4073ipsec_persist_connection (struct service *serv, u_int32_t flags)
4074{
4075#if !TARGET_OS_EMBEDDED
4076	u_int32_t laststatus = 0;
4077
4078	if (serv->persist_connect) {
4079		ipsec_updatephase(serv, IPSEC_INITIALIZE);
4080		IPSEC_UNASSERT(serv->u.ipsec);
4081		serv->flags |= flags;
4082		laststatus = serv->u.ipsec.laststatus;
4083		serv->u.ipsec.laststatus = IPSEC_NO_ERROR;
4084		serv->u.ipsec.next_address = 1;
4085		serv->u.ipsec.ping_count = 0;
4086		serv->u.ipsec.awaiting_peer_resp = 0;
4087		if (serv->u.ipsec.msg) {
4088			my_Deallocate(serv->u.ipsec.msg, serv->u.ipsec.msgtotallen + 1);
4089			serv->u.ipsec.msg = 0;
4090		}
4091		serv->u.ipsec.msglen = 0;
4092		serv->u.ipsec.msgtotallen = 0;
4093		if (serv->u.ipsec.modecfg_msg != NULL) {
4094			my_Deallocate(serv->u.ipsec.modecfg_msg, serv->u.ipsec.modecfg_msglen);
4095			serv->u.ipsec.modecfg_msg = NULL;
4096		}
4097		serv->u.ipsec.modecfg_msglen = 0;
4098		if (serv->u.ipsec.timerref) {
4099			CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), serv->u.ipsec.timerref, kCFRunLoopCommonModes);
4100			my_CFRelease(&serv->u.ipsec.timerref);
4101		}
4102		if (serv->u.ipsec.interface_timerref) {
4103			CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), serv->u.ipsec.interface_timerref, kCFRunLoopCommonModes);
4104			my_CFRelease(&serv->u.ipsec.interface_timerref);
4105		}
4106		if (serv->u.ipsec.port_mapping_timerref) {
4107			CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), serv->u.ipsec.port_mapping_timerref, kCFRunLoopCommonModes);
4108			my_CFRelease(&serv->u.ipsec.port_mapping_timerref);
4109		}
4110		my_CFRelease(&serv->u.ipsec.port_mapping_timerrun);
4111
4112		ipsec_log(LOG_NOTICE, CFSTR("IPSec Controller: reconnecting"));
4113		my_CFRelease(&serv->connection_nid);
4114		my_CFRelease(&serv->connection_nap);
4115		racoon_restart(serv, &serv->u.ipsec.peer_address);
4116		serv->persist_connect = 0;
4117		return TRUE;
4118	}
4119#endif
4120	return FALSE;
4121}
4122
4123/* -----------------------------------------------------------------------------
4124----------------------------------------------------------------------------- */
4125int ipsec_stop(struct service *serv, int signal)
4126{
4127	char			*errorstr;
4128	int				error;
4129	u_int32_t		flags = 0;
4130
4131	ipsec_log(LOG_INFO, CFSTR("IPSec Controller: ipsec_stop"));
4132
4133    SESSIONTRACERSTOP(serv);
4134    STOP_TRACKING_VPN_LOCATION(serv);
4135
4136	if (serv->u.ipsec.phase == IPSEC_PHASE1AUTH) {
4137		/* first, remove any pending authentication dialog */
4138		if (serv->userNotificationRef) {
4139			CFUserNotificationCancel(serv->userNotificationRef);
4140			CFRunLoopRemoveSource(CFRunLoopGetCurrent(), serv->userNotificationRLS, kCFRunLoopDefaultMode);
4141			my_CFRelease(&serv->userNotificationRef);
4142			my_CFRelease(&serv->userNotificationRLS);
4143		}
4144	}
4145
4146   // anticipate next phase
4147    switch (serv->u.ipsec.phase) {
4148
4149        case IPSEC_IDLE:
4150        case IPSEC_TERMINATE:
4151			/* special-case disconnect transitions? */
4152            ipsec_check_for_disconnect_by_recoverable_error(serv, &flags);
4153            return 0;
4154
4155        case IPSEC_WAITING:
4156        case IPSEC_RUNNING:
4157			/* special-case disconnect transitions? */
4158            ipsec_check_for_disconnect_by_recoverable_error(serv, &flags);
4159        default:
4160            ipsec_updatephase(serv, IPSEC_TERMINATE);
4161    }
4162
4163	IPSECLOGASLMSG("IPSec disconnecting from server %s\n", inet_ntoa(serv->u.ipsec.peer_address.sin_addr));
4164
4165	if (serv->u.ipsec.dnsPort) {
4166		mach_port_t mp = CFMachPortGetPort(serv->u.ipsec.dnsPort);
4167		CFMachPortInvalidate(serv->u.ipsec.dnsPort);
4168		CFRelease(serv->u.ipsec.dnsPort);
4169		serv->u.ipsec.dnsPort = NULL;
4170		getaddrinfo_async_cancel(mp);
4171	}
4172
4173	if (serv->u.ipsec.controlfd != -1) {
4174		racoon_send_cmd_disconnect(serv->u.ipsec.controlfd, serv->u.ipsec.peer_address.sin_addr.s_addr);
4175	}
4176
4177	if (ipsec_persist_connection(serv, flags) == TRUE) {
4178		return 0;
4179	}
4180
4181	if (serv->u.ipsec.policies_installed) {
4182		error = IPSecRemovePolicies(serv->u.ipsec.config, -1, &errorstr);
4183		if (error)
4184			ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Cannot remove policies, error '%s'"), errorstr);
4185
4186		IPSecRemoveSecurityAssociations((struct sockaddr *)&serv->u.ipsec.our_address, (struct sockaddr *)&serv->u.ipsec.peer_address);
4187
4188		serv->u.ipsec.policies_installed = 0;
4189	}
4190	if (serv->ne_sm_bridge != NULL) {
4191		ne_sm_bridge_request_uninstall(serv->ne_sm_bridge);
4192	}
4193	uninstall_mode_config(serv, TRUE);
4194
4195	if (serv->u.ipsec.config_applied) {
4196		error = IPSecRemoveConfiguration(serv->u.ipsec.config, &errorstr);
4197		if (error)
4198			ipsec_log(LOG_ERR, CFSTR("IPSec Controller: Cannot remove configuration, error '%s'"), errorstr);
4199		serv->u.ipsec.config_applied = 0;
4200	}
4201
4202    if (serv->u.ipsec.msg) {
4203        my_Deallocate(serv->u.ipsec.msg, serv->u.ipsec.msgtotallen + 1);
4204        serv->u.ipsec.msg = 0;
4205    }
4206    serv->u.ipsec.msglen = 0;
4207    serv->u.ipsec.msgtotallen = 0;
4208
4209	if (serv->u.ipsec.modecfg_msg != NULL) {
4210		my_Deallocate(serv->u.ipsec.modecfg_msg, serv->u.ipsec.modecfg_msglen);
4211		serv->u.ipsec.modecfg_msg = NULL;
4212	}
4213	serv->u.ipsec.modecfg_msglen = 0;
4214
4215    serv->uid = 0;
4216    serv->gid = 0;
4217    serv->bootstrap = 0;
4218
4219	serv->u.ipsec.ping_count = 0;
4220
4221	serv->u.ipsec.lower_interface[0] = 0;
4222	serv->u.ipsec.lower_interface_cellular = FALSE;
4223
4224	my_CFRelease(&serv->u.ipsec.resolvedAddress);
4225	serv->u.ipsec.resolvedAddress = 0;
4226
4227	if (serv->u.ipsec.controlref) {
4228
4229		CFSocketInvalidate(serv->u.ipsec.controlref);
4230		my_CFRelease(&serv->u.ipsec.controlref);
4231	}
4232	else if (serv->u.ipsec.controlfd) {
4233		close(serv->u.ipsec.controlfd);
4234	}
4235	serv->u.ipsec.controlfd	= -1;
4236
4237	if (serv->u.ipsec.eventref) {
4238
4239		CFSocketInvalidate(serv->u.ipsec.eventref);
4240		my_CFRelease(&serv->u.ipsec.eventref);
4241	}
4242	else if (serv->u.ipsec.eventfd) {
4243		close(serv->u.ipsec.eventfd);
4244	}
4245	serv->u.ipsec.eventfd	= -1;
4246
4247	scnc_bootstrap_dealloc(serv);
4248	scnc_ausession_dealloc(serv);
4249
4250	my_CFRelease(&serv->connectopts);
4251	my_CFRelease(&serv->u.ipsec.config);
4252
4253	if (serv->u.ipsec.timerref) {
4254		CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), serv->u.ipsec.timerref, kCFRunLoopCommonModes);
4255		my_CFRelease(&serv->u.ipsec.timerref);
4256	}
4257
4258	if (serv->u.ipsec.interface_timerref) {
4259		CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), serv->u.ipsec.interface_timerref, kCFRunLoopCommonModes);
4260		my_CFRelease(&serv->u.ipsec.interface_timerref);
4261	}
4262
4263#if TARGET_OS_EMBEDDED
4264	if (gNattKeepAliveInterval != -1) {
4265		int newval = gNattKeepAliveInterval;
4266		sysctlbyname("net.key.natt_keepalive_interval", 0, 0, &newval, sizeof(newval));
4267		gNattKeepAliveInterval = -1;
4268	}
4269#endif
4270
4271	if (serv->u.ipsec.port_mapping_timerref) {
4272		CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), serv->u.ipsec.port_mapping_timerref, kCFRunLoopCommonModes);
4273		my_CFRelease(&serv->u.ipsec.port_mapping_timerref);
4274	}
4275	my_CFRelease(&serv->u.ipsec.port_mapping_timerrun);
4276
4277	if (IPSEC_STATUS_IS_CLIENT_CERTIFICATE_INVALID(serv->u.ipsec.laststatus)) {
4278#if TARGET_OS_EMBEDDED
4279		if (serv->profileIdentifier) {
4280			CFStringRef msg = CFStringCreateWithFormat(0, 0, CFSTR("IPSec Error %d, Re-enroll"), serv->u.ipsec.laststatus);
4281			if (msg) {
4282				display_notification(serv, msg, 0, dialog_cert_fixme_type);
4283				CFRelease(msg);
4284			}
4285		}
4286		else
4287#endif
4288			display_notification(serv, NULL, serv->u.ipsec.laststatus, dialog_default_type);
4289	}
4290	else {
4291		if (!(serv->flags & FLAG_ONDEMAND)
4292			&& (serv->u.ipsec.laststatus != IPSEC_NO_ERROR))
4293			display_notification(serv, NULL, serv->u.ipsec.laststatus, dialog_default_type);
4294	}
4295
4296	ipsec_updatephase(serv, IPSEC_IDLE);
4297    	cleanup_dynamicstore((void *)serv);
4298	IPSEC_UNASSERT(serv->u.ipsec);
4299	CLEAR_VPN_PORTMAPPING(serv);
4300	serv->persist_connect = 0;
4301	serv->was_running = 0;
4302	service_ended(serv);
4303
4304	if (serv->ne_sm_bridge != NULL) {
4305		allow_dispose(serv);
4306	}
4307
4308	return 0;
4309}
4310
4311/* -----------------------------------------------------------------------------
4312----------------------------------------------------------------------------- */
4313int ipsec_getstatus(struct service *serv)
4314{
4315	SCNetworkConnectionStatus	status = kSCNetworkConnectionDisconnected;
4316
4317	switch (serv->u.ipsec.phase) {
4318		case IPSEC_INITIALIZE:
4319		case IPSEC_CONTACT:
4320		case IPSEC_PHASE1:
4321		case IPSEC_PHASE1AUTH:
4322		case IPSEC_PHASE2:
4323			status = kSCNetworkConnectionConnecting;
4324			break;
4325		case IPSEC_WAITING:
4326		case IPSEC_TERMINATE:
4327			status = kSCNetworkConnectionDisconnecting;
4328			break;
4329		case IPSEC_RUNNING:
4330			status = kSCNetworkConnectionConnected;
4331			break;
4332		case IPSEC_IDLE:
4333		default:
4334			status = kSCNetworkConnectionDisconnected;
4335	}
4336
4337	if (gSCNCVerbose) {
4338		ipsec_log(LOG_INFO, CFSTR("IPSec Controller: ipsec_getstatus = %s"),
4339			status == kSCNetworkConnectionDisconnected ? "Disconnected" :
4340			(status == kSCNetworkConnectionConnecting ? "Connecting" :
4341			(status == kSCNetworkConnectionDisconnecting ? "Disconnecting" :
4342			(status == kSCNetworkConnectionConnected ? "Connected" :
4343			("Unknown" )))));
4344	}
4345
4346	return status;
4347}
4348
4349/* -----------------------------------------------------------------------------
4350----------------------------------------------------------------------------- */
4351int ipsec_copyextendedstatus(struct service *serv, CFDictionaryRef *statusdict)
4352{
4353    CFMutableDictionaryRef dict = NULL;
4354	CFMutableDictionaryRef ipsecdict = NULL;
4355    char *addrstr;
4356	int error = 0;
4357
4358	*statusdict = NULL;
4359
4360    if ((dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0) {
4361		error = ENOMEM;
4362        goto fail;
4363	}
4364
4365    /* create and add IPSec dictionary */
4366    if ((ipsecdict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0) {
4367		error = ENOMEM;
4368        goto fail;
4369	}
4370
4371    AddNumber(ipsecdict, kSCPropNetIPSecStatus, serv->u.ipsec.phase);
4372
4373    if (serv->u.ipsec.phase != IPSEC_IDLE
4374		&& (addrstr = inet_ntoa(serv->u.ipsec.peer_address.sin_addr))) {
4375		AddString(ipsecdict, kRASPropIPSecRemoteAddress, addrstr);
4376	}
4377
4378    switch (serv->u.ipsec.phase) {
4379        case IPSEC_RUNNING:
4380			if (serv->ne_sm_bridge != NULL) {
4381				AddNumber64(ipsecdict, kSCPropNetIPSecConnectTime, ne_sm_bridge_get_connect_time(serv->ne_sm_bridge));
4382			} else {
4383				AddNumber(ipsecdict, kSCPropNetIPSecConnectTime, serv->connecttime);
4384			}
4385            break;
4386
4387        default:
4388			AddNumber(ipsecdict, CFSTR("LastCause"), serv->u.ipsec.laststatus);
4389    }
4390    CFDictionaryAddValue(dict, kSCEntNetIPSec, ipsecdict);
4391
4392    /* create and add IPv4 dictionary */
4393    if (serv->u.ipsec.phase == IPSEC_RUNNING) {
4394        CFMutableDictionaryRef ipv4dict = (CFMutableDictionaryRef)copyEntity(gDynamicStore, kSCDynamicStoreDomainState, serv->serviceID, kSCEntNetIPv4);
4395        if (ipv4dict) {
4396            CFDictionaryAddValue(dict, kSCEntNetIPv4, ipv4dict);
4397            CFRelease(ipv4dict);
4398        }
4399    }
4400
4401    AddNumber(dict, kSCNetworkConnectionStatus, ipsec_getstatus(serv));
4402
4403    ipsec_log(LOG_DEBUG, CFSTR("IPSec Controller: Copy Extended Status %@"), dict);
4404
4405	*statusdict = CFRetain(dict);
4406
4407fail:
4408    my_CFRelease(&ipsecdict);
4409    my_CFRelease(&dict);
4410    return error;
4411}
4412
4413/* -----------------------------------------------------------------------------
4414----------------------------------------------------------------------------- */
4415int ipsec_getconnectdata(struct service *serv, CFDictionaryRef *options, int all)
4416{
4417    CFDictionaryRef		opts;
4418    CFMutableDictionaryRef	mdict = NULL;
4419    CFDictionaryRef	dict;
4420	int err = 0;
4421
4422	*options = NULL;
4423
4424    /* return saved data */
4425    opts = serv->connectopts;
4426
4427    if (opts == 0) {
4428        // no data
4429        return 0;
4430    }
4431
4432	if (!all) {
4433		/* special code to remove secret information */
4434
4435		mdict = CFDictionaryCreateMutableCopy(0, 0, opts);
4436		if (mdict == 0) {
4437			// no data
4438			return 0;
4439		}
4440
4441		dict = CFDictionaryGetValue(mdict, kSCEntNetIPSec);
4442		if (dict && (CFGetTypeID(dict) == CFDictionaryGetTypeID())) {
4443			CFMutableDictionaryRef mdict1 = CFDictionaryCreateMutableCopy(0, 0, dict);
4444			if (mdict1) {
4445				CFDictionaryRemoveValue(mdict1, kSCPropNetIPSecSharedSecret);
4446				CFDictionarySetValue(mdict, kSCEntNetIPSec, mdict1);
4447				CFRelease(mdict1);
4448			}
4449		}
4450		*options = CFRetain(mdict);
4451	} else {
4452		*options = CFRetain(opts);
4453	}
4454
4455    my_CFRelease(&mdict);
4456    return err;
4457}
4458
4459/* -----------------------------------------------------------------------------
4460----------------------------------------------------------------------------- */
4461int ipsec_copystatistics(struct service *serv, CFDictionaryRef *statsdict)
4462{
4463    CFMutableDictionaryRef dict = NULL;
4464	CFMutableDictionaryRef ipsecdict = NULL;
4465	int error = 0;
4466
4467	*statsdict = NULL;
4468
4469	if (serv->u.ipsec.phase != IPSEC_RUNNING)
4470			return EINVAL;
4471
4472    if ((dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0) {
4473		error = ENOMEM;
4474		goto fail;
4475	}
4476
4477    /* create and add IPSec dictionary */
4478    if ((ipsecdict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0) {
4479		error = ENOMEM;
4480		goto fail;
4481	}
4482
4483	AddNumber(ipsecdict, kSCNetworkConnectionBytesIn, 0);
4484	AddNumber(ipsecdict, kSCNetworkConnectionBytesOut, 0);
4485	AddNumber(ipsecdict, kSCNetworkConnectionPacketsIn, 0);
4486	AddNumber(ipsecdict, kSCNetworkConnectionPacketsOut, 0);
4487	AddNumber(ipsecdict, kSCNetworkConnectionErrorsIn, 0);
4488	AddNumber(ipsecdict, kSCNetworkConnectionErrorsOut, 0);
4489
4490    CFDictionaryAddValue(dict, kSCEntNetIPSec, ipsecdict);
4491
4492	*statsdict = CFRetain(dict);
4493
4494fail:
4495    my_CFRelease(&ipsecdict);
4496    my_CFRelease(&dict);
4497    return error;
4498}
4499
4500void ipsec_device_lock(struct service *serv)
4501{
4502}
4503
4504void ipsec_device_unlock(struct service *serv)
4505{
4506	serv->u.ipsec.has_displayed_reenroll_alert = FALSE;
4507}
4508
4509/* -----------------------------------------------------------------------------
4510user has looged out
4511need to check the disconnect on logout flag for the ipsec interfaces
4512----------------------------------------------------------------------------- */
4513void ipsec_log_out(struct service *serv)
4514{
4515	if (serv->u.ipsec.phase != IPSEC_IDLE
4516		&& (serv->flags & FLAG_SETUP_DISCONNECTONLOGOUT))
4517		scnc_stop(serv, 0, SIGTERM, SCNC_STOP_USER_LOGOUT);
4518}
4519
4520/* -----------------------------------------------------------------------------
4521user has logged in
4522----------------------------------------------------------------------------- */
4523void ipsec_log_in(struct service *serv)
4524{
4525}
4526
4527/* -----------------------------------------------------------------------------
4528user has switched
4529need to check the disconnect on logout flags for the ppp interfaces
4530----------------------------------------------------------------------------- */
4531void ipsec_log_switch(struct service *serv)
4532{
4533
4534	switch (serv->u.ipsec.phase) {
4535		case IPSEC_IDLE:
4536			break;
4537
4538		default:
4539			if (serv->flags & FLAG_SETUP_DISCONNECTONFASTUSERSWITCH)
4540				scnc_stop(serv, 0, SIGTERM, SCNC_STOP_USER_SWITCH);
4541	}
4542}
4543
4544/* -----------------------------------------------------------------------------
4545ipv4 state has changed
4546----------------------------------------------------------------------------- */
4547void ipsec_ipv4_state_changed(struct service *serv)
4548{
4549}
4550
4551/* -----------------------------------------------------------------------------
4552system is asking permission to sleep
4553return if sleep is authorized
4554----------------------------------------------------------------------------- */
4555int ipsec_can_sleep(struct service	*serv)
4556{
4557
4558    // I refuse idle sleep if ppp is connected
4559	if (serv->u.ipsec.phase == IPSEC_RUNNING
4560		&& (serv->flags & FLAG_SETUP_PREVENTIDLESLEEP))
4561		return 0;
4562
4563    return 1;
4564}
4565
4566/* -----------------------------------------------------------------------------
4567system is going to sleep
4568disconnect services and return if a delay is needed
4569----------------------------------------------------------------------------- */
4570int ipsec_will_sleep(struct service	*serv, int checking)
4571{
4572	if (serv->u.ipsec.phase != IPSEC_IDLE && (serv->flags & FLAG_SETUP_DISCONNECTONSLEEP) && !checking) {
4573		scnc_stop(serv, 0, SIGTERM, SCNC_STOP_SYS_SLEEP);
4574	}
4575
4576	return 0;
4577}
4578
4579/* -----------------------------------------------------------------------------
4580system is waking up
4581----------------------------------------------------------------------------- */
4582void ipsec_wake_up(struct service	*serv)
4583{
4584	if (serv->u.ipsec.phase == IPSEC_RUNNING ||
4585		serv->u.ipsec.phase == IPSEC_WAITING) {
4586		if (DISCONNECT_VPN_IFOVERSLEPT(__FUNCTION__, serv, (char *)serv->if_name)) {
4587			return;
4588		} else if (DISCONNECT_VPN_IFLOCATIONCHANGED(serv)) {
4589			return;
4590		}
4591	}
4592}
4593
4594/* -----------------------------------------------------------------------------
4595----------------------------------------------------------------------------- */
4596static
4597void display_notification(struct service *serv, CFStringRef message, int errnum, int dialog_type)
4598{
4599    CFStringRef 	msg = NULL;
4600    CFMutableDictionaryRef 	dict = NULL;
4601    SInt32 			err;
4602
4603    if ((serv->flags & FLAG_ALERTERRORS) == 0)
4604        return;
4605
4606	if (message)
4607		msg = message;
4608	else {
4609		// filter out the following messages
4610		switch (errnum) {
4611			case IPSEC_NO_ERROR: /* IPSec Error 0 */
4612				return;
4613			case IPSEC_NETWORKCHANGE_ERROR: /* IPSec Error 15 */
4614				return;
4615#if TARGET_OS_EMBEDDED
4616			/* Errors 16, 17, 19 are not displayed on embedded os */
4617			case IPSEC_PEERDISCONNECT_ERROR: /* IPSec Error 16 */
4618			case IPSEC_PEERDEADETECTION_ERROR: /* IPSec Error 17 */
4619			case IPSEC_IDLETIMEOUT_ERROR: /* IPSec Error 19 */
4620				return;
4621#endif
4622		}
4623		msg = CFStringCreateWithFormat(0, 0, CFSTR("IPSec Error %d"), errnum);
4624	}
4625
4626    if (!msg || !CFStringGetLength(msg))
4627		goto done;
4628
4629	/* Are we trying to display the re-enrolling alert */
4630	if ((dialog_type == dialog_cert_fixme_type) && (serv->flags & FLAG_ONDEMAND)){
4631		/* check the last time we displayed this */
4632		if (serv->u.ipsec.has_displayed_reenroll_alert){
4633			goto done;
4634		}
4635	}
4636    dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
4637    if (!dict)
4638		goto done;
4639
4640	if (gIconURLRef)
4641		CFDictionaryAddValue(dict, kCFUserNotificationIconURLKey, gIconURLRef);
4642	if (gBundleURLRef)
4643		CFDictionaryAddValue(dict, kCFUserNotificationLocalizationURLKey, gBundleURLRef);
4644
4645	CFDictionaryAddValue(dict, kCFUserNotificationAlertMessageKey, msg);
4646	CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, CFSTR("VPN Connection"));
4647
4648	switch (dialog_type) {
4649		case dialog_has_disconnect_type:
4650			CFDictionaryAddValue(dict, kCFUserNotificationAlternateButtonTitleKey, CFSTR("Disconnect"));
4651			break;
4652		case dialog_cert_fixme_type:
4653			CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey, CFSTR("Ignore"));
4654			CFDictionaryAddValue(dict, kCFUserNotificationAlternateButtonTitleKey, CFSTR("Settings"));
4655			serv->u.ipsec.has_displayed_reenroll_alert = TRUE;
4656			break;
4657	}
4658
4659	if (serv->userNotificationRef) {
4660		err = CFUserNotificationUpdate(serv->userNotificationRef, 0, kCFUserNotificationNoteAlertLevel, dict);
4661	}
4662	else {
4663		serv->userNotificationRef = CFUserNotificationCreate(NULL, 0, kCFUserNotificationNoteAlertLevel, &err, dict);
4664		if (!serv->userNotificationRef)
4665			goto done;
4666
4667		serv->userNotificationRLS = CFUserNotificationCreateRunLoopSource(NULL, serv->userNotificationRef,
4668													user_notification_callback, 0);
4669		if (!serv->userNotificationRLS) {
4670			my_CFRelease(&serv->userNotificationRef);
4671			goto done;
4672		}
4673		CFRunLoopAddSource(CFRunLoopGetCurrent(), serv->userNotificationRLS, kCFRunLoopDefaultMode);
4674	}
4675
4676
4677done:
4678    my_CFRelease(&dict);
4679	if (!message)
4680		my_CFRelease(&msg);
4681}
4682
4683