1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25/* -----------------------------------------------------------------------------
26includes
27----------------------------------------------------------------------------- */
28#include <mach/mach.h>
29#include <string.h>
30#include <stdio.h>
31#include <termios.h>
32#include <unistd.h>
33#include <sys/errno.h>
34#include <sys/signal.h>
35#include <sys/param.h>
36#include <sys/socket.h>
37#include <net/if.h>
38#include <CoreFoundation/CoreFoundation.h>
39#include <netinet/in.h>
40#include <arpa/inet.h>
41#include <SystemConfiguration/SystemConfiguration.h>
42#include <SystemConfiguration/SCPrivate.h>      // for SCLog()
43#include <SystemConfiguration/SCValidation.h>
44#include <sys/ioctl.h>
45#include <net/if_dl.h>
46#include <net/if_utun.h>
47#include <notify.h>
48#include <sys/kern_control.h>
49#include <sys/sys_domain.h>
50#include <servers/bootstrap.h>
51#include <mach/task_special_ports.h>
52#include "pppcontroller_types.h"
53#include "pppcontroller.h"
54#include <bsm/libbsm.h>
55#include <sys/kern_event.h>
56#include <netinet/in_var.h>
57#include <netinet6/in6_var.h>
58#include <netinet6/nd6.h>
59#include <network_information.h>
60
61#include "ppp_msg.h"
62#include "../Family/if_ppplink.h"
63#include "scnc_main.h"
64#include "scnc_client.h"
65#include "scnc_utils.h"
66#include "ppp_option.h"
67#include "PPPControllerPriv.h"
68#include "../Family/ppp_domain.h"
69#include "../Helpers/pppd/pppd.h"
70#include "../Drivers/PPTP/PPTP-plugin/pptp.h"
71#include "../Drivers/L2TP/L2TP-plugin/l2tp.h"
72#include "../Drivers/PPPoE/PPPoE-extension/PPPoE.h"
73#include "ne_sm_bridge_private.h"
74
75/* -----------------------------------------------------------------------------
76definitions
77----------------------------------------------------------------------------- */
78#undef CONSTSTR
79#define CONSTSTR(str) (const char *)str
80
81/* -----------------------------------------------------------------------------
82Forward Declarations
83----------------------------------------------------------------------------- */
84
85
86/* -----------------------------------------------------------------------------
87globals
88----------------------------------------------------------------------------- */
89const char *scnc_ctrl_stopped = "Controller Stopped";
90const char *scnc_sys_sleep = "System will sleep";
91const char *scnc_usr_logout = "User Logged out";
92const char *scnc_usr_switch = "User Switched";
93const char *scnc_sock_disco = "Socket disconnect";
94const char *scnc_plugin_chg = "Plugin Change";
95const char *scnc_app_rem = "App removed";
96const char *scnc_usr_req = "User Requested";
97const char *scnc_term_all = "Terminated All";
98const char *scnc_serv_disp = "Service Disposed";
99const char *ppp_fatal = "Fatal Error";
100const char *ppp_option = "Option Error";
101const char *ppp_not_root = "Not Root";
102const char *ppp_no_kern = "No Kernel Support";
103const char *ppp_user_req = "User requested";
104const char *ppp_lock_fail = "Lock Failed";
105const char *ppp_open_fail = "Open Failed";
106const char *ppp_conn_fail = "Connect Failed";
107const char *ppp_pty_fail = "Pty command Failed";
108const char *ppp_nego_fail = "Negotiation Failed";
109const char *ppp_peer_auth_fail = "Peer Authentication Failed";
110const char *ppp_idle_tmo = "Idle Timeout";
111const char *ppp_sess_tmo = "Session Timeout";
112const char *ppp_callback = "Callback";
113const char *ppp_peer_dead = "Peer Dead";
114const char *ppp_disco_by_dev = "Disconnect by Device";
115const char *ppp_loopback = "Loopback Error";
116const char *ppp_init_fail = "Init Failed";
117const char *ppp_auth_fail = "Authentication to Peer Failed";
118const char *ppp_term_fail = "Terminal Failed";
119const char *ppp_dev_err = "Device Error";
120const char *ppp_peer_unauth = "Peer Not Authorized";
121const char *ppp_cnid_auth_fail = "CNID Authentication Failed";
122const char *ppp_peer_unreach = "Peer Unreachable";
123const char *ppp_dev_no_srvr = "No Server";
124const char *ppp_dev_no_ans = "No Answer";
125const char *ppp_dev_prot_err = "Protocol Error";
126const char *ppp_dev_net_chg = "Network Changed";
127const char *ppp_dev_psk = "Shared Secret";
128const char *ppp_dev_cert = "No Certificate";
129const char *ppp_dev_no_car = "No Carrier";
130const char *ppp_dev_no_num = "No Number";
131const char *ppp_dev_bad_script = "Bad Script";
132const char *ppp_dev_busy = "Busy";
133const char *ppp_dev_no_dial = "No Dial Tone";
134const char *ppp_dev_modem_err = "Modem Error";
135const char *ppp_dev_hang = "Hang-up";
136const char *ppp_dev_no_srvc = "No Service";
137const char *ppp_dev_no_ac = "No AC";
138const char *ppp_dev_no_ac_srvc = "No AC Service";
139const char *ppp_dev_conn_refuse = "Connection Refused";
140const char *ipsec_gen_err = "Generic Error";
141const char *ipsec_no_srvr_addr = "No Server Address";
142const char *ipsec_no_psk = "No Shared Secret";
143const char *ipsec_no_cert = "No Certificate";
144const char *ipsec_dns_err = "Resolve Address Error";
145const char *ipsec_no_local = "No Local Network";
146const char *ipsec_cfg_err = "Configuration Error";
147const char *ipsec_ctrl_err = "Racoon Control Error";
148const char *ipsec_conn_err = "Connection Error";
149const char *ipsec_nego_err = "Negotiation Error";
150const char *ipsec_psk_err = "Shared Secret Error";
151const char *ipsec_srvr_cert_err = "Server Certificate Error";
152const char *ipsec_cli_cert_err = "Client Certificate Error";
153const char *ipsec_xauth_err = "Xauth Error";
154const char *ipsec_net_chg = "Network Change";
155const char *ipsec_peer_disco = "Peer Disconnect";
156const char *ipsec_peer_dead = "Peer Dead";
157const char *ipsec_edge_err = "Edge Activation Error";
158const char *ipsec_idle_tmo = "Idle Timeout";
159const char *ipsec_cli_cert_pre = "Client Certificate premature";
160const char *ipsec_cli_cert_exp = "Client Certificate expired";
161const char *ipsec_srvr_cert_pre = "Server Certificate premature";
162const char *ipsec_srvr_cert_exp = "Server Certificate expired";
163const char *ipsec_srvr_cert_id = "Server Certificate identity incorrect";
164const char *vpn_gen_err = "Generic Error";
165const char *vpn_no_srvr_addr = "No Server Address";
166const char *vpn_no_cert = "No Certificate";
167const char *vpn_dns_err = "Resolve Address Error";
168const char *vpn_no_local = "No Local Network";
169const char *vpn_cfg_err = "Configuration Error";
170const char *vpn_ctrl_err = "Control Error";
171const char *vpn_conn_err = "Connection Error";
172const char *vpn_net_chg = "Network Change";
173const char *vpn_peer_disco = "Peer Disconnect";
174const char *vpn_peer_dead = "Peer Dead";
175const char *vpn_peer_unresp = "Peer not responding";
176const char *vpn_nego_err = "Negotiation Error";
177const char *vpn_xauth_err = "Xauth Error";
178const char *vpn_edge_err = "Edge Activation Error";
179const char *vpn_idle_tmo = "Idle Timeout";
180const char *vpn_addr_invalid = "Address invalid";
181const char *vpn_ap_req = "AP required";
182const char *vpn_cli_cert_pre = "Client Certificate premature";
183const char *vpn_cli_cert_exp = "Client Certificate expired";
184const char *vpn_srvr_cert_pre = "Server Certificate premature";
185const char *vpn_srvr_cert_exp = "Server Certificate expired";
186const char *vpn_srvr_cert_id = "Server Certificate identity incorrect";
187const char *vpn_plugin_upd = "Plugin update required";
188const char *vpn_plugin_dis = "Plugin disabled";
189
190
191
192/* -----------------------------------------------------------------------------
193 Given a string 'key' and a string prefix 'prefix',
194 return the next component in the slash '/' separated
195 key.  If no slash follows the prefix, return NULL.
196
197 Examples:
198 1. key = "a/b/c" prefix = "a/"    returns "b"
199 2. key = "a/b/c" prefix = "a/b/"  returns NULL
200----------------------------------------------------------------------------- */
201CFStringRef parse_component(CFStringRef key, CFStringRef prefix)
202{
203    CFMutableStringRef	comp;
204    CFRange		range;
205
206    if (!CFStringHasPrefix(key, prefix))
207    	return NULL;
208
209    comp = CFStringCreateMutableCopy(NULL, 0, key);
210    CFStringDelete(comp, CFRangeMake(0, CFStringGetLength(prefix)));
211    range = CFStringFind(comp, CFSTR("/"), 0);
212    if (range.location == kCFNotFound) {
213        CFRelease(comp);
214        return NULL;
215    }
216    range.length = CFStringGetLength(comp) - range.location;
217    CFStringDelete(comp, range);
218    return comp;
219}
220
221/* -----------------------------------------------------------------------------
222----------------------------------------------------------------------------- */
223CFDictionaryRef copyService(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID)
224{
225    CFTypeRef		data = NULL;
226    CFMutableDictionaryRef	service = NULL;
227    CFStringRef		key = NULL;
228    int			i;
229    CFStringRef         copy[] = {
230        kSCEntNetPPP,
231        kSCEntNetModem,
232        kSCEntNetInterface,
233    	kSCEntNetIPv4,
234    	kSCEntNetIPv6,
235#if !TARGET_OS_EMBEDDED
236    	kSCEntNetSMB,
237#endif
238        kSCEntNetDNS,
239        kSCEntNetL2TP,
240        kSCEntNetPPTP,
241        kSCEntNetIPSec,
242        NULL,
243    };
244
245    key = SCDynamicStoreKeyCreate(0, CFSTR("%@/%@/%@/%@"), domain, kSCCompNetwork, kSCCompService, serviceID);
246    if (key == 0)
247        goto fail;
248
249    data = SCDynamicStoreCopyValue(store, key);
250    if (data == 0) {
251		data = CFDictionaryCreate(NULL, 0, 0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
252		if (data == 0)
253			goto fail;
254	}
255
256    CFRelease(key);
257	key = NULL;
258
259    service = CFDictionaryCreateMutableCopy(NULL, 0, data);
260    if (service == 0)
261        goto fail;
262
263    CFRelease(data);
264
265    for (i = 0; copy[i]; i++) {
266        data = copyEntity(store, domain, serviceID, copy[i]);
267        if (data) {
268
269            CFDictionaryAddValue(service, copy[i], data);
270            CFRelease(data);
271        }
272    }
273
274    return service;
275
276fail:
277    if (key)
278        CFRelease(key);
279    if (data)
280        CFRelease(data);
281    if (service)
282        CFRelease(service);
283    return 0;
284}
285
286/* -----------------------------------------------------------------------------
287----------------------------------------------------------------------------- */
288CFDictionaryRef copyEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID, CFStringRef entity)
289{
290    CFTypeRef		data = NULL;
291    CFStringRef		key;
292
293    if (serviceID)
294        key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, domain, serviceID, entity);
295    else
296        key = SCDynamicStoreKeyCreateNetworkGlobalEntity(0, domain, entity);
297
298    if (key) {
299        data = SCDynamicStoreCopyValue(store, key);
300        CFRelease(key);
301    }
302    return data;
303}
304
305/* -----------------------------------------------------------------------------
306----------------------------------------------------------------------------- */
307int existEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID, CFStringRef entity)
308{
309    CFTypeRef		data;
310
311    data = copyEntity(store, domain, serviceID, entity);
312    if (data) {
313        CFRelease(data);
314        return 1;
315    }
316
317    return 0;
318}
319
320/* -----------------------------------------------------------------------------
321get a string from the dictionnary, in service/property
322----------------------------------------------------------------------------- */
323int getString(CFDictionaryRef service, CFStringRef property, u_char *str, u_int16_t maxlen)
324{
325    CFStringRef		string;
326    CFDataRef		ref;
327    const UInt8    *dataptr;
328    int            len;
329
330    str[0] = 0;
331    ref  = CFDictionaryGetValue(service, property);
332    if (ref) {
333        if (CFGetTypeID(ref) == CFStringGetTypeID()) {
334            CFStringGetCString((CFStringRef)ref, (char*)str, maxlen, kCFStringEncodingUTF8);
335            return 1;
336        }
337        else if (CFGetTypeID(ref) == CFDataGetTypeID()) {
338            CFStringEncoding    encoding;
339
340            if ((len = CFDataGetLength(ref)) && (dataptr = CFDataGetBytePtr(ref))){
341#if     __BIG_ENDIAN__
342                encoding = (*(dataptr + 1) == 0x00) ? kCFStringEncodingUTF16LE : kCFStringEncodingUTF16BE;
343#else   // __LITTLE_ENDIAN__
344                encoding = (*dataptr == 0x00) ? kCFStringEncodingUTF16BE : kCFStringEncodingUTF16LE;
345#endif
346                string = CFStringCreateWithBytes(NULL, (const UInt8 *)dataptr, len, encoding, FALSE);
347                if (string) {
348                    CFStringGetCString((CFStringRef)string, (char*)str, maxlen, kCFStringEncodingUTF8);
349                    CFRelease(string);
350                    return 1;
351                }
352            }
353        }
354    }
355    return 0;
356}
357
358/* -----------------------------------------------------------------------------
359get a number from the dictionnary, in service/property
360----------------------------------------------------------------------------- */
361int getNumber(CFDictionaryRef dict, CFStringRef property, u_int32_t *outval)
362{
363    CFNumberRef		ref;
364
365    ref  = CFDictionaryGetValue(dict, property);
366    if (ref && (CFGetTypeID(ref) == CFNumberGetTypeID())) {
367        CFNumberGetValue(ref, kCFNumberSInt32Type, outval);
368        return 1;
369    }
370    return 0;
371}
372
373/* -----------------------------------------------------------------------------
374----------------------------------------------------------------------------- */
375int getNumberFromEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID,
376        CFStringRef entity, CFStringRef property, u_int32_t *outval)
377{
378    CFTypeRef		data;
379    int 		ok = 0;
380
381    if ((data = copyEntity(store, domain, serviceID, entity))) {
382        ok = getNumber(data, property, outval);
383        CFRelease(data);
384    }
385    return ok;
386}
387
388/* -----------------------------------------------------------------------------
389----------------------------------------------------------------------------- */
390int getStringFromEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID,
391        CFStringRef entity, CFStringRef property, u_char *str, u_int16_t maxlen)
392{
393    CFTypeRef		data;
394    int 		ok = 0;
395
396    data = copyEntity(store, domain, serviceID, entity);
397    if (data) {
398        ok = getString(data, property, str, maxlen);
399        CFRelease(data);
400    }
401    return ok;
402}
403
404/* -----------------------------------------------------------------------------
405----------------------------------------------------------------------------- */
406CFStringRef copyCFStringFromEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID,
407        CFStringRef entity, CFStringRef property)
408{
409    CFTypeRef		data;
410    CFStringRef		string, ret = 0;
411
412    data = copyEntity(store, domain, serviceID, entity);
413    if (data) {
414        string  = CFDictionaryGetValue(data, property);
415        if (string && (CFGetTypeID(string) == CFStringGetTypeID())) {
416            CFRetain(string);
417            ret = string;
418        }
419
420        CFRelease(data);
421    }
422    return ret;
423}
424
425/* -----------------------------------------------------------------------------
426----------------------------------------------------------------------------- */
427u_int32_t CFStringAddrToLong(CFStringRef string)
428{
429    char 	str[100];
430    u_int32_t	ret = 0;
431
432    if (string) {
433	str[0] = 0;
434        CFStringGetCString(string, str, sizeof(str), kCFStringEncodingMacRoman);
435        ret = ntohl(inet_addr(str));
436    }
437    return ret;
438}
439
440/* -----------------------------------------------------------------------------
441----------------------------------------------------------------------------- */
442int getAddressFromEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID,
443        CFStringRef entity, CFStringRef property, u_int32_t *outval)
444{
445    CFTypeRef		data;
446    int 		ok = 0;
447    CFArrayRef		array;
448
449    data = copyEntity(store, domain, serviceID, entity);
450    if (data) {
451        array = CFDictionaryGetValue(data, property);
452        if (array && CFArrayGetCount(array)) {
453            *outval = CFStringAddrToLong(CFArrayGetValueAtIndex(array, 0));
454            ok = 1;
455        }
456        CFRelease(data);
457    }
458    return ok;
459}
460
461/* -----------------------------------------------------------------------------
462----------------------------------------------------------------------------- */
463Boolean my_CFEqual(CFTypeRef obj1, CFTypeRef obj2)
464{
465    if (obj1 == NULL && obj2 == NULL)
466        return true;
467    else if (obj1 == NULL || obj2 == NULL)
468        return false;
469
470    return CFEqual(obj1, obj2);
471}
472
473/* -----------------------------------------------------------------------------
474----------------------------------------------------------------------------- */
475void my_CFRelease(void *t)
476{
477    void * * obj = (void * *)t;
478    if (obj && *obj) {
479	CFRelease(*obj);
480	*obj = NULL;
481    }
482    return;
483}
484
485/* -----------------------------------------------------------------------------
486----------------------------------------------------------------------------- */
487void my_close(int fd)
488{
489    if (fd != -1)
490        close(fd);
491}
492
493/* -----------------------------------------------------------------------------
494----------------------------------------------------------------------------- */
495CFTypeRef my_CFRetain(CFTypeRef obj)
496{
497    if (obj)
498        CFRetain(obj);
499	return obj;
500}
501
502/* -----------------------------------------------------------------------------
503----------------------------------------------------------------------------- */
504Boolean isDictionary (CFTypeRef obj)
505{
506    return (obj && CFGetTypeID(obj) == CFDictionaryGetTypeID());
507}
508
509/* -----------------------------------------------------------------------------
510----------------------------------------------------------------------------- */
511Boolean isArray (CFTypeRef obj)
512{
513    return (obj && CFGetTypeID(obj) == CFArrayGetTypeID());
514}
515
516/* -----------------------------------------------------------------------------
517----------------------------------------------------------------------------- */
518Boolean isString (CFTypeRef obj)
519{
520    return (obj && CFGetTypeID(obj) == CFStringGetTypeID());
521}
522
523/* -----------------------------------------------------------------------------
524----------------------------------------------------------------------------- */
525Boolean isNumber (CFTypeRef obj)
526{
527    return (obj && CFGetTypeID(obj) == CFNumberGetTypeID());
528}
529
530/* -----------------------------------------------------------------------------
531----------------------------------------------------------------------------- */
532Boolean isData (CFTypeRef obj)
533{
534    return (obj && CFGetTypeID(obj) == CFDataGetTypeID());
535}
536
537
538/* -----------------------------------------------------------------------------
539----------------------------------------------------------------------------- */
540void AddNumber(CFMutableDictionaryRef dict, CFStringRef property, u_int32_t number)
541{
542   CFNumberRef num;
543    num = CFNumberCreate(NULL, kCFNumberSInt32Type, &number);
544    if (num) {
545        CFDictionaryAddValue(dict, property, num);
546        CFRelease(num);
547    }
548}
549
550/* -----------------------------------------------------------------------------
551----------------------------------------------------------------------------- */
552void AddNumber64(CFMutableDictionaryRef dict, CFStringRef property, u_int64_t number)
553{
554   CFNumberRef num;
555    num = CFNumberCreate(NULL, kCFNumberSInt64Type, &number);
556    if (num) {
557        CFDictionaryAddValue(dict, property, num);
558        CFRelease(num);
559    }
560}
561
562/* -----------------------------------------------------------------------------
563----------------------------------------------------------------------------- */
564void AddString(CFMutableDictionaryRef dict, CFStringRef property, char *string)
565{
566    CFStringRef str;
567    str = CFStringCreateWithCString(NULL, string, kCFStringEncodingUTF8);
568    if (str) {
569        CFDictionaryAddValue(dict, property, str);
570        CFRelease(str);
571    }
572}
573
574/* -----------------------------------------------------------------------------
575----------------------------------------------------------------------------- */
576void AddNumberFromState(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef entity, CFStringRef property, CFMutableDictionaryRef dict)
577{
578    u_int32_t 	lval;
579
580    if (getNumberFromEntity(store, kSCDynamicStoreDomainState, serviceID, entity, property, &lval))
581        AddNumber(dict, property, lval);
582}
583
584/* -----------------------------------------------------------------------------
585----------------------------------------------------------------------------- */
586void AddStringFromState(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef entity, CFStringRef property, CFMutableDictionaryRef dict)
587{
588    CFStringRef	string;
589
590    if ((string = copyCFStringFromEntity(store, kSCDynamicStoreDomainState, serviceID, entity, property))) {
591        CFDictionaryAddValue(dict, property, string);
592        CFRelease(string);
593    }
594}
595
596/* -------------------------------------------------------------------------------------------
597------------------------------------------------------------------------------------------- */
598CFDataRef Serialize(CFPropertyListRef obj, void **data, u_int32_t *dataLen)
599{
600    CFDataRef           	xml;
601
602    xml = CFPropertyListCreateXMLData(NULL, obj);
603    if (xml) {
604        *data = (void*)CFDataGetBytePtr(xml);
605        *dataLen = CFDataGetLength(xml);
606    }
607    return xml;
608}
609
610/* -------------------------------------------------------------------------------------------
611------------------------------------------------------------------------------------------- */
612CFPropertyListRef Unserialize(void *data, u_int32_t dataLen)
613{
614    CFDataRef           	xml;
615    CFPropertyListRef	ref = 0;
616
617    xml = CFDataCreate(NULL, data, dataLen);
618    if (xml) {
619        ref = CFPropertyListCreateFromXMLData(NULL,
620                xml,  kCFPropertyListImmutable, NULL);
621        CFRelease(xml);
622    }
623
624    return ref;
625}
626
627/* -----------------------------------------------------------------------------
628----------------------------------------------------------------------------- */
629void *my_Allocate(int size)
630{
631	void			*addr;
632	kern_return_t	status;
633
634	status = vm_allocate(mach_task_self(), (vm_address_t *)&addr, size, TRUE);
635	if (status != KERN_SUCCESS) {
636		return 0;
637	}
638
639	return addr;
640}
641
642/* -----------------------------------------------------------------------------
643----------------------------------------------------------------------------- */
644void my_Deallocate(void * addr, int size)
645{
646	kern_return_t	status;
647
648	if (addr == 0)
649		return;
650
651	status = vm_deallocate(mach_task_self(), (vm_address_t)addr, size);
652	if (status != KERN_SUCCESS) {
653	}
654
655	return;
656}
657
658// ----------------------------------------------------------------------------
659//	GetIntFromDict
660// ----------------------------------------------------------------------------
661Boolean GetIntFromDict (CFDictionaryRef dict, CFStringRef property, u_int32_t *outval, u_int32_t defaultval)
662{
663    CFNumberRef		ref;
664
665	ref  = CFDictionaryGetValue(dict, property);
666	if (isNumber(ref)
667		&&  CFNumberGetValue(ref, kCFNumberSInt32Type, outval))
668		return TRUE;
669
670	*outval = defaultval;
671	return FALSE;
672}
673
674// ----------------------------------------------------------------------------
675//	GetStrFromDict
676// ----------------------------------------------------------------------------
677int GetStrFromDict (CFDictionaryRef dict, CFStringRef property, char *outstr, int maxlen, char *defaultval)
678{
679    CFStringRef		ref;
680
681	ref  = CFDictionaryGetValue(dict, property);
682	if (!isString(ref)
683		|| !CFStringGetCString(ref, outstr, maxlen, kCFStringEncodingUTF8))
684		strncpy(outstr, defaultval, maxlen);
685
686	return strlen(outstr);
687}
688
689// ----------------------------------------------------------------------------
690//	GetStrAddrFromDict
691// ----------------------------------------------------------------------------
692Boolean GetStrAddrFromDict (CFDictionaryRef dict, CFStringRef property, char *outstr, int maxlen)
693{
694    CFStringRef		ref;
695	in_addr_t               addr;
696
697	ref  = CFDictionaryGetValue(dict, property);
698	if (isString(ref)
699			&& CFStringGetCString(ref, outstr, maxlen, kCFStringEncodingUTF8)) {
700					addr = inet_addr(outstr);
701					return addr != INADDR_NONE;
702	}
703
704	return FALSE;
705}
706
707// ----------------------------------------------------------------------------
708//	GetStrNetFromDict
709// ----------------------------------------------------------------------------
710Boolean GetStrNetFromDict (CFDictionaryRef dict, CFStringRef property, char *outstr, int maxlen)
711{
712    CFStringRef		ref;
713	in_addr_t               net;
714
715	ref  = CFDictionaryGetValue(dict, property);
716	if (isString(ref)
717			&& CFStringGetCString(ref, outstr, maxlen, kCFStringEncodingUTF8)) {
718			net = inet_network(outstr);
719			return net != INADDR_NONE;// && net != 0;
720	}
721
722	return FALSE;
723}
724
725
726
727/* -----------------------------------------------------------------------------
728publish a dictionnary entry in the cache, given a key
729----------------------------------------------------------------------------- */
730int publish_keyentry(SCDynamicStoreRef store, CFStringRef key, CFStringRef entry, CFTypeRef value)
731{
732    CFMutableDictionaryRef	dict;
733    CFPropertyListRef		ref;
734
735    if ((ref = SCDynamicStoreCopyValue(store, key))) {
736        dict = CFDictionaryCreateMutableCopy(0, 0, ref);
737        CFRelease(ref);
738    }
739    else
740        dict = CFDictionaryCreateMutable(0, 0,
741                &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
742
743    if (dict == 0)
744        return 0;
745
746    CFDictionarySetValue(dict,  entry, value);
747    SCDynamicStoreSetValue(store, key, dict);
748    CFRelease(dict);
749
750    return 1;
751 }
752/* -----------------------------------------------------------------------------
753unpublish a dictionnary entry from the cache, given the dict key
754----------------------------------------------------------------------------- */
755int unpublish_keyentry(SCDynamicStoreRef store, CFStringRef key, CFStringRef entry)
756{
757    CFMutableDictionaryRef	dict;
758    CFPropertyListRef		ref;
759
760    if ((ref = SCDynamicStoreCopyValue(store, key))) {
761        if ((dict = CFDictionaryCreateMutableCopy(0, 0, ref))) {
762            CFDictionaryRemoveValue(dict, entry);
763            SCDynamicStoreSetValue(store, key, dict);
764            CFRelease(dict);
765        }
766        CFRelease(ref);
767    }
768    return 0;
769}
770
771
772/* -----------------------------------------------------------------------------
773publish a numerical entry in the cache, given a dictionary
774----------------------------------------------------------------------------- */
775int publish_dictnumentry(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef dict, CFStringRef entry, int val)
776{
777    int			ret = ENOMEM;
778    CFNumberRef		num;
779    CFStringRef		key;
780
781    key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dict);
782    if (key) {
783        num = CFNumberCreate(NULL, kCFNumberIntType, &val);
784        if (num) {
785            ret = publish_keyentry(store, key, entry, num);
786            CFRelease(num);
787            ret = 0;
788        }
789        CFRelease(key);
790    }
791    return ret;
792}
793
794
795/* -----------------------------------------------------------------------------
796 unpublish a dictionnary entry from the cache, given the dict name
797 ----------------------------------------------------------------------------- */
798int unpublish_dictentry(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef dict, CFStringRef entry)
799{
800    int			ret = ENOMEM;
801    CFStringRef		key;
802
803    key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dict);
804    if (key) {
805        ret = unpublish_keyentry(store, key, entry);
806        CFRelease(key);
807        ret = 0;
808    }
809    return ret;
810}
811
812/* -----------------------------------------------------------------------------
813 publishes multiple dictionaries to the cache, given the dict names and the dicts. Indices must match up exactly
814 ----------------------------------------------------------------------------- */
815int publish_multiple_dicts(SCDynamicStoreRef store, CFStringRef serviceID, CFArrayRef dictNames, CFArrayRef dicts)
816{
817    CFDictionaryRef     dict = NULL;
818    CFStringRef         dictName = NULL;
819    int                 i;
820    CFStringRef         key;
821    CFMutableDictionaryRef   keys_to_add;
822    int                 numDicts;
823    int                 ret = ENOMEM;
824
825	if (!store)
826		return -1;
827
828    /* Check arrays */
829    if (!dictNames || !dicts)
830        return -1;
831
832    /* Verify sizes */
833    numDicts = CFArrayGetCount(dictNames);
834    if (numDicts != CFArrayGetCount(dicts))
835        return -1;
836
837    keys_to_add = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
838
839    for (i = 0; i < numDicts; i++) {
840        dictName = CFArrayGetValueAtIndex(dictNames, i);
841        dict = CFArrayGetValueAtIndex(dicts, i);
842        if (isA_CFString(dictName) && isA_CFDictionary(dict)) {
843            key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dictName);
844            if (key) {
845                CFDictionaryAddValue(keys_to_add, key, dict);
846                CFRelease(key);
847            }
848        }
849    }
850
851    SCDynamicStoreSetMultiple(store, keys_to_add, NULL, NULL);
852
853    my_CFRelease(&keys_to_add);
854
855    return ret;
856}
857
858/* -----------------------------------------------------------------------------
859 unpublish a dictionnary entry from the cache, given the dict name
860 ----------------------------------------------------------------------------- */
861int unpublish_dict(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef dict)
862{
863    int			ret = ENOMEM;
864    CFStringRef		key;
865
866	if (!store)
867		return -1;
868
869	if (dict)
870		key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dict);
871	else
872		key = SCDynamicStoreKeyCreate(0, CFSTR("%@/%@/%@/%@"), kSCDynamicStoreDomainState, kSCCompNetwork, kSCCompService, serviceID);
873    if (key) {
874        SCDynamicStoreRemoveValue(store, key);
875        CFRelease(key);
876		ret = 0;
877    }
878
879    return ret;
880}
881
882/* -----------------------------------------------------------------------------
883 unpublish multiple dictionary entries from the cache, given an array of dict names
884 ----------------------------------------------------------------------------- */
885int unpublish_multiple_dicts(SCDynamicStoreRef store, CFStringRef serviceID, CFArrayRef dictNames, Boolean removeService)
886{
887    CFStringRef         dictName = NULL;
888    int                 i;
889    CFStringRef         key;
890    CFMutableArrayRef   keys_to_remove;
891    int                 numDictNames;
892    int                 ret = ENOMEM;
893
894	if (!store)
895		return -1;
896
897    keys_to_remove = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
898
899    if (dictNames) {
900        numDictNames = CFArrayGetCount(dictNames);
901        for (i = 0; i < numDictNames; i++) {
902            dictName = CFArrayGetValueAtIndex(dictNames, i);
903            if (isA_CFString(dictName)) {
904                key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dictName);
905                if (key) {
906                    CFArrayAppendValue(keys_to_remove, key);
907                    CFRelease(key);
908                }
909            }
910        }
911    }
912
913    if (removeService) {
914        key = SCDynamicStoreKeyCreate(0, CFSTR("%@/%@/%@/%@"), kSCDynamicStoreDomainState, kSCCompNetwork, kSCCompService, serviceID);
915        if (key) {
916            CFArrayAppendValue(keys_to_remove, key);
917            CFRelease(key);
918        }
919    }
920
921    SCDynamicStoreSetMultiple(store, NULL, keys_to_remove, NULL);
922
923    my_CFRelease(&keys_to_remove);
924
925    return ret;
926}
927
928/* -----------------------------------------------------------------------------
929publish a string entry in the cache, given a dictionary
930----------------------------------------------------------------------------- */
931int publish_dictstrentry(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef dict, CFStringRef entry, char *str, int encoding)
932{
933
934    int			ret = ENOMEM;
935    CFStringRef 	ref;
936    CFStringRef		key;
937
938    key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dict);
939    if (key) {
940        ref = CFStringCreateWithCString(NULL, str, encoding);
941        if (ref) {
942            ret = publish_keyentry(store, key, entry, ref);
943            CFRelease(ref);
944            ret = 0;
945        }
946        CFRelease(key);
947    }
948    return ret;
949}
950
951/* -----------------------------------------------------------------------------
952 return f s CFString contains an IP address
953 ----------------------------------------------------------------------------- */
954int
955cfstring_is_ip(CFStringRef str)
956{
957	char *buf;
958	struct in_addr ip = { 0 };
959	CFIndex l;
960	int n, result;
961	CFRange range;
962
963	if (!isString(str) || (l = CFStringGetLength(str)) == 0)
964		return 0;
965
966	buf = malloc(l+1);
967	if (buf == NULL) {
968		SCLog(TRUE, LOG_ERR, CFSTR("Failed to allocate memory"));
969		return 0;
970	}
971
972	range = CFRangeMake(0, l);
973	n = CFStringGetBytes(str, range, kCFStringEncodingMacRoman,
974						 0, FALSE, (UInt8 *)buf, l, &l);
975	buf[l] = '\0';
976
977	result = inet_aton(buf, &ip);
978	free(buf);
979	return result;
980}
981
982/* -----------------------------------------------------------------------------
983 ----------------------------------------------------------------------------- */
984CFStringRef
985copyPrimaryService (SCDynamicStoreRef store)
986{
987    CFDictionaryRef	dict;
988    CFStringRef		key;
989    CFStringRef		primary = NULL;
990
991    if ((key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
992                                                          kSCDynamicStoreDomainState,
993                                                          kSCEntNetIPv4)) == NULL) {
994        return NULL;
995    }
996
997    dict = SCDynamicStoreCopyValue(store, key);
998    CFRelease(key);
999    if (isA_CFDictionary(dict)) {
1000        primary = CFDictionaryGetValue(dict,
1001                                       kSCDynamicStorePropNetPrimaryService);
1002
1003        primary = isA_CFString(primary);
1004        if (primary)
1005            CFRetain(primary);
1006    }
1007    if (dict != NULL) {
1008        CFRelease(dict);
1009    }
1010    return primary;
1011}
1012
1013/* -----------------------------------------------------------------------------
1014 ----------------------------------------------------------------------------- */
1015Boolean UpdatePasswordPrefs(CFStringRef serviceID, CFStringRef interfaceType, SCNetworkInterfacePasswordType passwordType,
1016								   CFStringRef passwordEncryptionKey, CFStringRef passwordEncryptionValue, CFStringRef logTitle)
1017{
1018	SCPreferencesRef		prefs = NULL;
1019	SCNetworkServiceRef		service = NULL;
1020	SCNetworkInterfaceRef	interface = NULL;
1021	CFMutableDictionaryRef	newConfig = NULL;
1022	CFDictionaryRef			config;
1023	Boolean					ok, locked = FALSE, success = FALSE;
1024
1025	prefs = SCPreferencesCreate(NULL, CFSTR("UpdatePassword"), NULL);
1026	if (prefs == NULL) {
1027		SCLog(TRUE, LOG_ERR, CFSTR("%@: SCPreferencesCreate fails"), logTitle);
1028        goto done;
1029	}
1030	// lock the prefs
1031	ok = SCPreferencesLock(prefs, TRUE);
1032	if (!ok) {
1033		SCLog(TRUE, LOG_ERR, CFSTR("%@: SCPreferencesLock fails"), logTitle);
1034        goto done;
1035	}
1036
1037	locked = TRUE;
1038
1039	// get the service
1040	service = SCNetworkServiceCopy(prefs, serviceID);
1041	if (service == NULL) {
1042		SCLog(TRUE, LOG_ERR, CFSTR("%@: SCNetworkServiceCopy fails"), logTitle);
1043        goto done;
1044	}
1045	// get the interface associated with the service
1046	interface = SCNetworkServiceGetInterface(service);
1047	if ((interface == NULL) || !CFEqual(SCNetworkInterfaceGetInterfaceType(interface), interfaceType)) {
1048		SCLog(TRUE, LOG_ERR, CFSTR("%@: interface not %@"), logTitle, interfaceType);
1049        goto done;
1050	}
1051
1052	// remove any current password (from the system keychain)
1053	if (SCNetworkInterfaceCheckPassword(interface, passwordType)) {
1054        // if password current associated with this interface
1055        ok = SCNetworkInterfaceRemovePassword(interface,  passwordType);
1056        if (!ok) {
1057			SCLog(TRUE, LOG_ERR, CFSTR("%@: SCNetworkInterfaceRemovePassword fails"), logTitle);
1058        }
1059	}
1060
1061	// update passworEncryptionKey
1062	config = SCNetworkInterfaceGetConfiguration(interface);
1063
1064	if (config != NULL) {
1065        newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
1066	}
1067	else {
1068        newConfig = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1069	}
1070
1071	if (newConfig == NULL) {
1072		SCLog(TRUE, LOG_ERR, CFSTR("%@: cannot allocate new interface configuration"), logTitle);
1073		goto done;
1074	}
1075
1076	if (passwordEncryptionValue) {
1077		CFDictionarySetValue(newConfig, passwordEncryptionKey, passwordEncryptionValue);
1078	} else {
1079		CFDictionaryRemoveValue( newConfig, passwordEncryptionKey);
1080	}
1081
1082	ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
1083	if ( !ok ) {
1084		SCLog(TRUE, LOG_ERR, CFSTR("%@: SCNetworkInterfaceSetConfiguration fails"), logTitle);
1085		goto done;
1086	}
1087
1088	// commit & apply the changes
1089	ok = SCPreferencesCommitChanges(prefs);
1090	if (!ok) {
1091		SCLog(TRUE, LOG_ERR, CFSTR("%@: SCPreferencesCommitChanges fails"), logTitle);
1092		goto done;
1093	}
1094	ok = SCPreferencesApplyChanges(prefs);
1095	if (!ok) {
1096		SCLog(TRUE, LOG_ERR, CFSTR("%@: SCPreferencesApplyChanges fails"), logTitle);
1097		goto done;
1098	}
1099
1100	success = TRUE;
1101
1102	done :
1103	if (newConfig!= NULL) {
1104		CFRelease(newConfig);
1105	}
1106	if (service != NULL) {
1107		CFRelease(service);
1108	}
1109	if (locked) {
1110		SCPreferencesUnlock(prefs);
1111	}
1112	if (prefs != NULL) {
1113		CFRelease(prefs);
1114	}
1115	return success;
1116}
1117
1118
1119/* -----------------------------------------------------------------------------
1120set the sa_family field of a struct sockaddr, if it exists.
1121----------------------------------------------------------------------------- */
1122#define SET_SA_FAMILY(addr, family)		\
1123    bzero((char *) &(addr), sizeof(addr));	\
1124    addr.sa_family = (family); 			\
1125    addr.sa_len = sizeof(addr);
1126
1127/* -----------------------------------------------------------------------------
1128Config the interface MTU
1129----------------------------------------------------------------------------- */
1130int set_ifmtu(char *ifname, int mtu)
1131{
1132    struct ifreq ifr;
1133	int ip_sockfd;
1134
1135    ip_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
1136    if (ip_sockfd < 0) {
1137		syslog(LOG_INFO, "sifmtu: cannot create ip socket, %s",
1138	       strerror(errno));
1139		return 0;
1140	}
1141
1142    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1143    ifr.ifr_mtu = mtu;
1144    ioctl(ip_sockfd, SIOCSIFMTU, (caddr_t) &ifr);
1145
1146	close(ip_sockfd);
1147	return 1;
1148}
1149
1150/* -----------------------------------------------------------------------------
1151Config the interface IP addresses and netmask
1152----------------------------------------------------------------------------- */
1153int set_ifaddr(char *ifname, u_int32_t o, u_int32_t h, u_int32_t m)
1154{
1155    struct ifaliasreq ifra __attribute__ ((aligned (4)));   // Wcast-align fix - force alignment
1156	int ip_sockfd;
1157
1158    ip_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
1159    if (ip_sockfd < 0) {
1160		syslog(LOG_INFO, "sifaddr: cannot create ip socket, %s",
1161	       strerror(errno));
1162		return 0;
1163	}
1164
1165    strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
1166
1167    SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
1168    (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
1169
1170	SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
1171    (ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
1172
1173	if (m != 0) {
1174		SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
1175		(ALIGNED_CAST(struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
1176    }
1177	else
1178		bzero(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
1179
1180    if (ioctl(ip_sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
1181		if (errno != EEXIST) {
1182			//error("Couldn't set interface address: %m");
1183			close(ip_sockfd);
1184			return 0;
1185		}
1186		//warning("Couldn't set interface address: Address %I already exists", o);
1187    }
1188
1189	close(ip_sockfd);
1190	return 1;
1191}
1192
1193/* -----------------------------------------------------------------------------
1194Clear the interface IP addresses, and delete routes
1195 * through the interface if possible
1196 ----------------------------------------------------------------------------- */
1197int clear_ifaddr(char *ifname, u_int32_t o, u_int32_t h)
1198{
1199	struct ifreq ifr __attribute__ ((aligned (4)));       // Wcast-align fix - force alignment
1200	int ip_sockfd;
1201
1202	ip_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
1203	if (ip_sockfd < 0) {
1204		syslog(LOG_INFO, "cifaddr: cannot create ip socket, %s",
1205		   strerror(errno));
1206		return 0;
1207	}
1208
1209	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1210	SET_SA_FAMILY(ifr.ifr_ifru.ifru_addr, AF_INET);
1211	(ALIGNED_CAST(struct sockaddr_in *) &ifr.ifr_ifru.ifru_addr)->sin_addr.s_addr = o;
1212	if (ioctl(ip_sockfd, SIOCDIFADDR, (caddr_t) &ifr) < 0) {
1213		close(ip_sockfd);
1214		return 0;
1215	}
1216
1217	close(ip_sockfd);
1218	return 1;
1219}
1220
1221/* -----------------------------------------------------------------------------
1222----------------------------------------------------------------------------- */
1223void
1224in6_len2mask(struct in6_addr *mask, int len)
1225{
1226	int i;
1227
1228	bzero(mask, sizeof(*mask));
1229	for (i = 0; i < len / 8; i++)
1230		mask->s6_addr[i] = 0xff;
1231	if (len % 8)
1232		mask->s6_addr[i] = (0xff00 >> (len % 8)) & 0xff;
1233}
1234
1235/* -----------------------------------------------------------------------------
1236mask address according to the mask
1237----------------------------------------------------------------------------- */
1238void
1239in6_maskaddr(struct in6_addr *addr, struct in6_addr *mask)
1240{
1241	int i;
1242
1243	for (i = 0; i < sizeof(struct in6_addr); i++)
1244		addr->s6_addr[i] &= mask->s6_addr[i];
1245}
1246
1247/* -----------------------------------------------------------------------------
1248----------------------------------------------------------------------------- */
1249void
1250in6_addr2net(struct in6_addr *addr, int prefix, struct in6_addr *net) {
1251
1252    struct in6_addr	mask;
1253	int i;
1254
1255	in6_len2mask(&mask, prefix);
1256
1257	for (i = 0; i < sizeof(mask.s6_addr); i++)
1258		(*net).s6_addr[i] = (*addr).s6_addr[i] & (mask).s6_addr[i];
1259
1260}
1261
1262/* -----------------------------------------------------------------------------
1263Config the interface IPv6 addresses
1264ll_addr must be a 64 bits address.
1265----------------------------------------------------------------------------- */
1266int set_ifaddr6 (char *ifname, struct in6_addr *addr, int prefix)
1267{
1268	int s;
1269	struct in6_aliasreq addreq6;
1270	struct in6_addr		mask;
1271
1272	s = socket(AF_INET6, SOCK_DGRAM, 0);
1273	if (s < 0) {
1274		syslog(LOG_ERR, "set_ifaddr6: can't create IPv6 socket, %s",
1275			   strerror(errno));
1276		return 0;
1277	}
1278
1279	memset(&addreq6, 0, sizeof(addreq6));
1280	strlcpy(addreq6.ifra_name, ifname, sizeof(addreq6.ifra_name));
1281
1282	/* my addr */
1283	addreq6.ifra_addr.sin6_family = AF_INET6;
1284	addreq6.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
1285	memcpy(&addreq6.ifra_addr.sin6_addr, addr, sizeof(struct in6_addr));
1286
1287	/* prefix mask: 128bit */
1288	addreq6.ifra_prefixmask.sin6_family = AF_INET6;
1289	addreq6.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
1290	in6_len2mask(&mask, prefix);
1291    memcpy(&addreq6.ifra_prefixmask.sin6_addr, &mask, sizeof(struct in6_addr));
1292
1293	/* address lifetime (infty) */
1294	addreq6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
1295	addreq6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
1296
1297	if (IN6_IS_ADDR_LINKLOCAL(addr)) {
1298		if (ioctl(s, SIOCLL_START, &addreq6) < 0) {
1299			syslog(LOG_ERR, "set_ifaddr6: can't set link-local IPv6 address, %s",
1300				   strerror(errno));
1301			close(s);
1302			return 0;
1303		}
1304	} else {
1305		if (ioctl(s, SIOCAIFADDR_IN6, &addreq6) < 0) {
1306			syslog(LOG_ERR, "set_ifaddr6: can't set IPv6 address, %s",
1307				   strerror(errno));
1308			close(s);
1309			return 0;
1310		}
1311	}
1312
1313	close(s);
1314	return 1;
1315}
1316
1317/* -----------------------------------------------------------------------------
1318Clear the interface IPv6 addresses
1319 ----------------------------------------------------------------------------- */
1320int clear_ifaddr6 (char *ifname, struct in6_addr *addr)
1321{
1322    int s;
1323    struct in6_ifreq ifreq6;
1324
1325   s = socket(AF_INET6, SOCK_DGRAM, 0);
1326    if (s < 0) {
1327        syslog(LOG_ERR, "set_ifaddr6: can't create IPv6 socket, %s",
1328	       strerror(errno));
1329        return 0;
1330    }
1331
1332    memset(&ifreq6, 0, sizeof(ifreq6));
1333    strlcpy(ifreq6.ifr_name, ifname, sizeof(ifreq6.ifr_name));
1334
1335    /* my addr */
1336    ifreq6.ifr_ifru.ifru_addr.sin6_family = AF_INET6;
1337    ifreq6.ifr_ifru.ifru_addr.sin6_len = sizeof(struct sockaddr_in6);
1338    memcpy(&ifreq6.ifr_ifru.ifru_addr.sin6_addr, addr, sizeof(struct in6_addr));
1339
1340    if (ioctl(s, SIOCDIFADDR_IN6, &ifreq6) < 0) {
1341        syslog(LOG_ERR, "set_ifaddr6: can't set IPv6 address, %s",
1342	       strerror(errno));
1343        close(s);
1344        return 0;
1345    }
1346
1347    close(s);
1348    return 1;
1349}
1350
1351
1352/* ----------------------------------------------------------------------------
1353----------------------------------------------------------------------------- */
1354const char *inet_sockaddr_to_p(struct sockaddr *addr, char *buf, int buflen)
1355{
1356	void *p;
1357
1358    // Wcast-align fixes (void*) OK - inet_ntop has no alignment requirement
1359	switch (addr->sa_family) {
1360		case AF_INET:
1361            p = &((struct sockaddr_in *)(void*)addr)->sin_addr;
1362            break;
1363		case AF_INET6:
1364            p = &((struct sockaddr_in6 *)(void*)addr)->sin6_addr;
1365			break;
1366		default:
1367			return NULL;
1368	}
1369
1370	return inet_ntop(addr->sa_family, p, buf, buflen);
1371}
1372
1373/* ----------------------------------------------------------------------------
1374----------------------------------------------------------------------------- */
1375int inet_p_to_sockaddr(char *buf, struct sockaddr *addr, int addrlen)
1376{
1377    bzero(addr, addrlen);
1378
1379    // Wcast-align fixes (void*) OK - inet_pton has no alignment requirement
1380	if (addrlen >= sizeof(struct sockaddr_in)
1381		&& inet_pton(AF_INET, buf, &((struct sockaddr_in *)(void*)addr)->sin_addr)) {
1382        addr->sa_len = sizeof(struct sockaddr_in);
1383        addr->sa_family = AF_INET;
1384        return 1;
1385	}
1386
1387	if (addrlen >= sizeof(struct sockaddr_in6)
1388		&& inet_pton(AF_INET6, buf, &((struct sockaddr_in6 *)(void*)addr)->sin6_addr)) {
1389        addr->sa_len = sizeof(struct sockaddr_in6);
1390        addr->sa_family = AF_INET6;
1391        return 1;
1392	}
1393
1394	return 0;
1395}
1396
1397
1398/* ----------------------------------------------------------------------------
1399return the default interface name and gateway for a given protocol
1400----------------------------------------------------------------------------- */
1401Boolean copyGateway(SCDynamicStoreRef store, u_int8_t family, char *ifname, int ifnamesize, struct sockaddr *gateway, int gatewaysize)
1402{
1403	CFDictionaryRef dict;
1404	CFStringRef key, string;
1405	Boolean found_interface = FALSE;
1406	Boolean found_router = FALSE;
1407
1408 	if (ifname)
1409		ifname[0] = 0;
1410	if (gateway)
1411		bzero(gateway, gatewaysize);
1412
1413	if (family != AF_INET && family != AF_INET6)
1414		return FALSE;
1415
1416	key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState,
1417		(family == AF_INET) ? kSCEntNetIPv4 : kSCEntNetIPv6);
1418    if (key) {
1419      dict = SCDynamicStoreCopyValue(store, key);
1420		CFRelease(key);
1421        if (dict) {
1422
1423			if ((string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface))) {
1424				found_interface = TRUE;
1425				if (ifname)
1426					CFStringGetCString(string, ifname, ifnamesize, kCFStringEncodingUTF8);
1427			}
1428			if ((string = CFDictionaryGetValue(dict, (family == AF_INET) ? kSCPropNetIPv4Router : kSCPropNetIPv6Router))) {
1429				char routeraddress[256];
1430				routeraddress[0] = 0;
1431				CFStringGetCString(string, (char*)routeraddress, sizeof(routeraddress), kCFStringEncodingUTF8);
1432				if (routeraddress[0]) {
1433					struct sockaddr_storage addr;
1434					if (inet_p_to_sockaddr(routeraddress, (struct sockaddr *)&addr, sizeof(addr))) {
1435						found_router = TRUE;
1436						if (gateway && gatewaysize >= addr.ss_len)
1437							bcopy(&addr, gateway, addr.ss_len);
1438					}
1439				}
1440			}
1441			CFRelease(dict);
1442		}
1443	}
1444	return (found_interface && found_router);
1445}
1446
1447/* ----------------------------------------------------------------------------
1448return TRUE if there is a default interface and gateway for a given protocol
1449----------------------------------------------------------------------------- */
1450Boolean hasGateway(SCDynamicStoreRef store, u_int8_t family)
1451{
1452	return copyGateway(store, family, 0, 0, 0, 0);
1453
1454}
1455
1456/* ----------------------------------------------------------------------------
1457 Create a "NULL Service" primary IPv6 dictionary for the dynamic store. This
1458 prevents any other service from becoming primary on IPv6.
1459 ----------------------------------------------------------------------------- */
1460#ifndef kIsNULL
1461#define kIsNULL		CFSTR("IsNULL") /* CFBoolean */
1462#endif
1463CFDictionaryRef create_ipv6_dummy_primary(char *if_name)
1464{
1465	CFMutableArrayRef		array;
1466	CFMutableDictionaryRef	ipv6_dict;
1467	int						isprimary = 1;
1468	CFNumberRef				num;
1469	CFStringRef				str;
1470
1471	/* create the IPv6 dictionnary */
1472	if ((ipv6_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0)
1473		return NULL;
1474
1475	if ((array = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks))) {
1476		CFArrayAppendValue(array, CFSTR("::1"));
1477		CFDictionarySetValue(ipv6_dict, kSCPropNetIPv6Addresses, array);
1478		CFRelease(array);
1479	}
1480
1481	CFDictionarySetValue(ipv6_dict, kSCPropNetIPv6Router, CFSTR("::1"));
1482
1483	num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &isprimary);
1484	if (num) {
1485		CFDictionarySetValue(ipv6_dict, kSCPropNetOverridePrimary, num);
1486		CFRelease(num);
1487	}
1488
1489	CFDictionarySetValue(ipv6_dict, kIsNULL, kCFBooleanTrue);
1490
1491	if (if_name) {
1492		if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), if_name))) {
1493			CFDictionarySetValue(ipv6_dict, kSCPropInterfaceName, str);
1494			CFRelease(str);
1495		}
1496	}
1497
1498	return ipv6_dict;
1499}
1500
1501/* ----------------------------------------------------------------------------
1502get dictionary for ip addresses to publish later to configd
1503use new state information model
1504----------------------------------------------------------------------------- */
1505CFDictionaryRef create_stateaddr(SCDynamicStoreRef store, CFStringRef serviceID, char *if_name, u_int32_t server, u_int32_t o,
1506			u_int32_t h, u_int32_t m, int isprimary, CFArrayRef includedRoutes, CFArrayRef excludedRoutes)
1507{
1508    struct in_addr		addr;
1509    CFMutableArrayRef		array;
1510    CFMutableDictionaryRef	ipv4_dict;
1511    CFStringRef			str;
1512    CFNumberRef		num;
1513	SCNetworkServiceRef netservRef;
1514
1515    /* create the IPV4 dictionnary */
1516    if ((ipv4_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0)
1517        return NULL;
1518
1519	/* set the ip address src and dest arrays */
1520    if ((array = CFArrayCreateMutable(0, 1, &kCFTypeArrayCallBacks))) {
1521        addr.s_addr = o;
1522        if ((str = CFStringCreateWithFormat(0, 0, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) {
1523            CFArrayAppendValue(array, str);
1524            CFRelease(str);
1525            CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4Addresses, array);
1526        }
1527        CFRelease(array);
1528    }
1529
1530    /* set the router */
1531    addr.s_addr = h;
1532    if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) {
1533        CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4Router, str);
1534        CFRelease(str);
1535    }
1536
1537	num = CFNumberCreate(NULL, kCFNumberIntType, &isprimary);
1538	if (num) {
1539        CFDictionarySetValue(ipv4_dict, kSCPropNetOverridePrimary, num);
1540		CFRelease(num);
1541	}
1542
1543	if (if_name) {
1544		if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), if_name))) {
1545			CFDictionarySetValue(ipv4_dict, kSCPropInterfaceName, str);
1546			CFRelease(str);
1547		}
1548	}
1549
1550    /* set the server */
1551    addr.s_addr = server;
1552    if ((str = CFStringCreateWithFormat(NULL, NULL, CFSTR(IP_FORMAT), IP_LIST(&addr.s_addr)))) {
1553		CFDictionarySetValue(ipv4_dict, CFSTR("ServerAddress"), str);
1554        CFRelease(str);
1555    }
1556
1557#if 0
1558    /* add the network signature */
1559    if (network_signature) {
1560		if (str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), network_signature)) {
1561			CFDictionarySetValue(ipv4_dict, CFSTR("NetworkSignature"), str);
1562			CFRelease(str);
1563		}
1564	}
1565#endif
1566
1567
1568	/* rank service, to prevent it from becoming primary */
1569	if (!isprimary) {
1570		netservRef = _SCNetworkServiceCopyActive(store, serviceID);
1571		if (netservRef) {
1572			SCNetworkServiceSetPrimaryRank(netservRef, kSCNetworkServicePrimaryRankLast);
1573			CFRelease(netservRef);
1574		}
1575	}
1576
1577	if (includedRoutes) {
1578		CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4AdditionalRoutes, includedRoutes);
1579	}
1580
1581	if (excludedRoutes) {
1582		CFDictionarySetValue(ipv4_dict, kSCPropNetIPv4ExcludedRoutes, excludedRoutes);
1583	}
1584
1585    return ipv4_dict;
1586}
1587
1588/* -----------------------------------------------------------------------------
1589 get dns information
1590 ----------------------------------------------------------------------------- */
1591CFDictionaryRef create_dns(SCDynamicStoreRef store, CFStringRef serviceID, CFArrayRef dns, CFStringRef domain, CFArrayRef supp_domains, Boolean neverSearchDomains)
1592{
1593    CFMutableDictionaryRef	dict = NULL;
1594    CFStringRef			key = NULL;
1595    CFPropertyListRef		ref;
1596
1597    if (store == NULL)
1598        return NULL;
1599
1600    key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, kSCEntNetDNS);
1601    if (!key)
1602        goto end;
1603
1604    if ((ref = SCDynamicStoreCopyValue(store, key))) {
1605        dict = CFDictionaryCreateMutableCopy(0, 0, ref);
1606        CFRelease(ref);
1607    } else
1608        dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1609
1610    if (!dict || (CFGetTypeID(dict) != CFDictionaryGetTypeID()))
1611        goto end;
1612
1613    CFDictionarySetValue(dict, kSCPropNetDNSServerAddresses, dns);
1614
1615    if (domain)
1616		CFDictionarySetValue(dict, kSCPropNetDNSDomainName, domain);
1617
1618    if (supp_domains)
1619		CFDictionarySetValue(dict, kSCPropNetDNSSupplementalMatchDomains, supp_domains);
1620
1621#ifndef kSCPropNetDNSSupplementalMatchDomainsNoSearch
1622#define kSCPropNetDNSSupplementalMatchDomainsNoSearch CFSTR("SupplementalMatchDomainsNoSearch")
1623#endif
1624
1625    if (neverSearchDomains) {
1626        AddNumber(dict, kSCPropNetDNSSupplementalMatchDomainsNoSearch, 1);
1627    }
1628
1629	/* warn lookupd of upcoming change */
1630	notify_post("com.apple.system.dns.delay");
1631
1632end:
1633    my_CFRelease(&key);
1634    return dict;
1635
1636}
1637
1638/* -----------------------------------------------------------------------------
1639 ----------------------------------------------------------------------------- */
1640Boolean equal_address(struct sockaddr *addr1, struct sockaddr *addr2)
1641{
1642
1643	if (addr1->sa_family != addr2->sa_family)
1644		return FALSE;
1645
1646    /* Wcast-align fixes - don't use assignement or standard compare for ptrs of unknown alignment */
1647	if (addr1->sa_family == AF_INET) {
1648        return (!bcmp(&((struct sockaddr_in *)(void*)addr1)->sin_addr.s_addr,
1649                      &((struct sockaddr_in *)(void*)addr2)->sin_addr.s_addr,
1650                      sizeof(struct in_addr)));
1651	}
1652
1653	if (addr1->sa_family == AF_INET6) {
1654		return (!bcmp(&((struct sockaddr_in6 *)(void*)addr1)->sin6_addr,
1655                      &((struct sockaddr_in6 *)(void*)addr2)->sin6_addr,
1656                      sizeof(struct in6_addr)));
1657	}
1658
1659	return FALSE;
1660}
1661
1662/* -----------------------------------------------------------------------------
1663    add/remove a route via a gateway
1664----------------------------------------------------------------------------- */
1665int
1666route_gateway(int cmd, struct sockaddr *dest, struct sockaddr *mask, struct sockaddr *gateway, int use_gway_flag, int use_blackhole_flag)
1667{
1668    int 			len;
1669    int 			rtm_seq = 0;
1670
1671    struct rtmsg_in4 {
1672	struct rt_msghdr	hdr;
1673	struct sockaddr_in	dst;
1674	struct sockaddr_in	gway;
1675	struct sockaddr_in	mask;
1676    };
1677    struct rtmsg_in6 {
1678	struct rt_msghdr	hdr;
1679	struct sockaddr_in6	dst;
1680	struct sockaddr_in6	gway;
1681	struct sockaddr_in6	mask;
1682    };
1683
1684    int 			sockfd = -1;
1685    struct rtmsg_in6 rtmsg; // use rtmsg_in6 since it is the bigger one;
1686
1687	if (dest == NULL || (dest->sa_family != AF_INET
1688		&& dest->sa_family != AF_INET6))
1689		return -1;
1690
1691    if ((sockfd = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)) < 0) {
1692	syslog(LOG_INFO, "route_gateway: open routing socket failed, %s",
1693	       strerror(errno));
1694	return (-1);
1695    }
1696
1697    memset(&rtmsg, 0, sizeof(rtmsg));
1698
1699	// fill in header, which is common to IPv4 and IPv6
1700    rtmsg.hdr.rtm_type = cmd;
1701    rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC;
1702    if (use_gway_flag)
1703        rtmsg.hdr.rtm_flags |= RTF_GATEWAY;
1704    if (use_blackhole_flag)
1705        rtmsg.hdr.rtm_flags |= RTF_BLACKHOLE;
1706    rtmsg.hdr.rtm_version = RTM_VERSION;
1707    rtmsg.hdr.rtm_seq = ++rtm_seq;
1708    rtmsg.hdr.rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY;
1709
1710	// then fill in address specific portion
1711	if (dest->sa_family == AF_INET) {
1712		struct rtmsg_in4 *rtmsg4 = (struct rtmsg_in4 *)&rtmsg;
1713
1714		bcopy(dest, &rtmsg4->dst, sizeof(rtmsg4->dst));
1715		if (gateway)
1716			bcopy(gateway, &rtmsg4->gway, sizeof(rtmsg4->gway));
1717		if (mask)
1718			bcopy(mask, &rtmsg4->mask, sizeof(rtmsg4->mask));
1719
1720		len = sizeof(struct rtmsg_in4);
1721	}
1722	else {
1723		struct rtmsg_in6 *rtmsg6 = (struct rtmsg_in6 *)&rtmsg;
1724
1725		bcopy(dest, &rtmsg6->dst, sizeof(rtmsg6->dst));
1726		if (gateway)
1727			bcopy(gateway, &rtmsg6->gway, sizeof(rtmsg6->gway));
1728		if (mask)
1729			bcopy(mask, &rtmsg6->mask, sizeof(rtmsg6->mask));
1730
1731		len = sizeof(struct rtmsg_in6);
1732	}
1733
1734	rtmsg.hdr.rtm_msglen = len;
1735    if (write(sockfd, &rtmsg, len) < 0) {
1736		syslog((cmd == RTM_DELETE)? LOG_DEBUG : LOG_ERR, "route_gateway: write routing socket failed, %s", strerror(errno));
1737
1738#if 0
1739		/* print routing message for debugging */
1740		char buf[256];
1741		syslog(LOG_ERR, "-------");
1742		struct rtmsg_in4 *rtmsg4 = (struct rtmsg_in4 *)&rtmsg;
1743		inet_sockaddr_to_p(dest->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->dst : (struct sockaddr *)&rtmsg.dst, buf, sizeof(buf));
1744		syslog(LOG_ERR, "route_gateway: rtmsg.dst = %s", buf);
1745		inet_sockaddr_to_p(dest->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->gway : (struct sockaddr *)&rtmsg.gway, buf, sizeof(buf));
1746		syslog(LOG_ERR, "route_gateway: rtmsg.gway = %s", buf);
1747		inet_sockaddr_to_p(dest->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->mask : (struct sockaddr *)&rtmsg.mask, buf, sizeof(buf));
1748		syslog(LOG_ERR, "route_gateway: rtmsg.mask = %s", buf);
1749		syslog(LOG_ERR, "-------");
1750#endif
1751
1752		close(sockfd);
1753		return (-1);
1754    }
1755
1756    close(sockfd);
1757    return (0);
1758}
1759
1760/* -----------------------------------------------------------------------------
1761add/remove a host route
1762----------------------------------------------------------------------------- */
1763boolean_t
1764set_host_gateway(int cmd, struct sockaddr *host, struct sockaddr *gateway, char *ifname, int isnet)
1765{
1766    int 			len;
1767    int 			rtm_seq = 0;
1768    struct rtmsg_in4 {
1769	struct rt_msghdr	hdr;
1770	struct sockaddr_in	dst;
1771	struct sockaddr_in	gway;
1772	struct sockaddr_in	mask;
1773	struct sockaddr_dl	link;
1774    };
1775    struct rtmsg_in6 {
1776	struct rt_msghdr	hdr;
1777	struct sockaddr_in6	dst;
1778	struct sockaddr_in6	gway;
1779	struct sockaddr_in6	mask;
1780	struct sockaddr_dl	link;
1781    };
1782
1783    int 			sockfd = -1;
1784    struct rtmsg_in6 rtmsg; // use rtmsg_in6 since it is the bigger one;
1785	struct sockaddr_dl *link;
1786	struct in6_addr     ip6_zeros;
1787    struct in_addr      ip4_zeros;
1788
1789	if (host == NULL || (host->sa_family != AF_INET
1790		&& host->sa_family != AF_INET6))
1791		return FALSE;
1792
1793    if ((sockfd = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)) < 0) {
1794	syslog(LOG_INFO, "host_gateway: open routing socket failed, %s",
1795	       strerror(errno));
1796	return (FALSE);
1797    }
1798
1799    memset(&rtmsg, 0, sizeof(rtmsg));
1800    rtmsg.hdr.rtm_type = cmd;
1801    rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC;
1802    if (isnet)
1803        rtmsg.hdr.rtm_flags |= RTF_CLONING;
1804    else
1805        rtmsg.hdr.rtm_flags |= RTF_HOST;
1806	bzero(&ip6_zeros, sizeof(ip6_zeros));
1807    bzero(&ip4_zeros, sizeof(ip4_zeros));
1808    // Wcast-align fix - use memcmp for unaligned comparison
1809    if (gateway && (((gateway->sa_family == AF_INET && memcmp(&((struct sockaddr_in *)(void*)gateway)->sin_addr.s_addr, &ip4_zeros, sizeof(struct in_addr)))) ||
1810		(gateway->sa_family == AF_INET6 && memcmp(&((struct sockaddr_in6 *)(void*)gateway)->sin6_addr, &ip6_zeros, sizeof(struct in6_addr))))) {
1811        rtmsg.hdr.rtm_flags |= RTF_GATEWAY;
1812	}
1813
1814	rtmsg.hdr.rtm_version = RTM_VERSION;
1815    rtmsg.hdr.rtm_seq = ++rtm_seq;
1816    rtmsg.hdr.rtm_addrs = RTA_DST | RTA_NETMASK | RTA_GATEWAY;
1817
1818	if (host->sa_family == AF_INET) {
1819		struct rtmsg_in4 *rtmsg4 = (struct rtmsg_in4 *)&rtmsg;
1820
1821		bcopy(host, &rtmsg4->dst, sizeof(rtmsg4->dst));
1822
1823		if (gateway)
1824			bcopy(gateway, &rtmsg4->gway, sizeof(rtmsg4->gway));
1825
1826		rtmsg4->mask.sin_len = sizeof(rtmsg4->mask);
1827		rtmsg4->mask.sin_family = AF_INET;
1828		rtmsg4->mask.sin_addr.s_addr = 0xFFFFFFFF;
1829
1830		len = sizeof(struct rtmsg_in4);
1831		link = &rtmsg4->link;
1832	}
1833	else {
1834		struct rtmsg_in6 *rtmsg6 = (struct rtmsg_in6 *)&rtmsg;
1835
1836		bcopy(host, &rtmsg6->dst, sizeof(rtmsg6->dst));
1837
1838		if (gateway)
1839			bcopy(gateway, &rtmsg6->gway, sizeof(rtmsg6->gway));
1840
1841		rtmsg6->mask.sin6_len = sizeof(rtmsg6->mask);
1842		rtmsg6->mask.sin6_family = AF_INET6;
1843		rtmsg6->mask.sin6_addr.__u6_addr.__u6_addr32[0] = 0xFFFFFFFF;
1844		rtmsg6->mask.sin6_addr.__u6_addr.__u6_addr32[1] = 0xFFFFFFFF;
1845		rtmsg6->mask.sin6_addr.__u6_addr.__u6_addr32[2] = 0xFFFFFFFF;
1846		rtmsg6->mask.sin6_addr.__u6_addr.__u6_addr32[3] = 0xFFFFFFFF;
1847
1848		len = sizeof(struct rtmsg_in6);
1849		link = &rtmsg6->link;
1850	}
1851
1852    if (ifname) {
1853		link->sdl_len = sizeof(rtmsg.link);
1854		link->sdl_family = AF_LINK;
1855		link->sdl_nlen = MIN(strlen(ifname), sizeof(link->sdl_data));
1856		rtmsg.hdr.rtm_addrs |= RTA_IFP;
1857		bcopy(ifname, link->sdl_data, link->sdl_nlen);
1858    }
1859    else {
1860		/* no link information */
1861		len -= sizeof(rtmsg.link);
1862    }
1863
1864    rtmsg.hdr.rtm_msglen = len;
1865    if (write(sockfd, &rtmsg, len) < 0) {
1866		syslog((cmd == RTM_DELETE)? LOG_DEBUG : LOG_ERR, "host_gateway: write routing socket failed, command %d, %s", cmd, strerror(errno));
1867
1868#if 0
1869		/* print routing message for debugging */
1870		char buf[256];
1871		syslog(LOG_ERR, "********");
1872		struct rtmsg_in4 *rtmsg4 = (struct rtmsg_in4 *)&rtmsg;
1873		syslog(LOG_ERR, "host_gateway: dest->sa_family = %d rtmsg.hdr.rtm_msglen = %d", host->sa_family, rtmsg.hdr.rtm_msglen);
1874		inet_sockaddr_to_p(host->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->dst : (struct sockaddr *)&rtmsg.dst, buf, sizeof(buf));
1875		syslog(LOG_ERR, "host_gateway: rtmsg.dst = %s", buf);
1876		inet_sockaddr_to_p(host->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->gway : (struct sockaddr *)&rtmsg.gway, buf, sizeof(buf));
1877		syslog(LOG_ERR, "host_gateway: rtmsg.gway = %s", buf);
1878		inet_sockaddr_to_p(host->sa_family == AF_INET ? (struct sockaddr *)&rtmsg4->mask : (struct sockaddr *)&rtmsg.mask, buf, sizeof(buf));
1879		syslog(LOG_ERR, "host_gateway: rtmsg.mask = %s", buf);
1880		syslog(LOG_ERR, "********");
1881#endif
1882		close(sockfd);
1883		return (FALSE);
1884    }
1885
1886    close(sockfd);
1887    return (TRUE);
1888}
1889
1890/* ----------------------------------------------------------------------------
1891 get proxies using to publish to configd
1892 ----------------------------------------------------------------------------- */
1893CFDictionaryRef create_proxies(SCDynamicStoreRef store, CFStringRef serviceID, int autodetect, CFStringRef server, int port, int bypasslocal,
1894		CFStringRef exceptionlist, CFArrayRef supp_domains)
1895{
1896	int				val, ret = -1;
1897    CFStringRef		cfstr = NULL;
1898    CFArrayRef		cfarray;
1899    CFNumberRef		cfnum,  cfone = NULL;
1900    CFMutableDictionaryRef	proxies_dict = NULL;
1901
1902    if ((proxies_dict = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0)
1903        goto fail;
1904
1905	val = 1;
1906	cfone = CFNumberCreate(NULL, kCFNumberIntType, &val);
1907	if (cfone == NULL)
1908		goto fail;
1909
1910	if (autodetect) {
1911		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesProxyAutoDiscoveryEnable, cfone);
1912	}
1913	else if (server) {
1914
1915		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesFTPEnable, cfone);
1916		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPEnable, cfone);
1917		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPSEnable, cfone);
1918
1919		cfnum = CFNumberCreate(NULL, kCFNumberIntType, &port);
1920		if (cfnum == NULL)
1921			goto fail;
1922
1923		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesFTPPort, cfnum);
1924		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPPort, cfnum);
1925		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPSPort, cfnum);
1926		CFRelease(cfnum);
1927
1928		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesFTPProxy, server);
1929		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPProxy, server);
1930		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesHTTPSProxy, server);
1931
1932		cfnum = CFNumberCreate(NULL, kCFNumberIntType, &bypasslocal);
1933		if (cfnum == NULL)
1934			goto fail;
1935		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesExcludeSimpleHostnames, cfnum);
1936		CFRelease(cfnum);
1937
1938		if (exceptionlist) {
1939			cfarray = CFStringCreateArrayBySeparatingStrings(NULL, exceptionlist, CFSTR(";"));
1940			if (cfarray) {
1941				CFDictionarySetValue(proxies_dict, kSCPropNetProxiesExceptionsList, cfarray);
1942				CFRelease(cfarray);
1943			}
1944		}
1945	}
1946
1947#ifndef kSCPropNetProxiesSupplementalMatchDomains
1948#define kSCPropNetProxiesSupplementalMatchDomains kSCPropNetDNSSupplementalMatchDomains
1949#endif
1950
1951    if (supp_domains)
1952		CFDictionarySetValue(proxies_dict, kSCPropNetProxiesSupplementalMatchDomains, supp_domains);
1953
1954	ret = 0;
1955
1956fail:
1957
1958    my_CFRelease(&cfone);
1959	my_CFRelease(&cfstr);
1960    return proxies_dict;
1961}
1962
1963/* -----------------------------------------------------------------------------
1964 Create the new tun interface, and return the socket
1965 ----------------------------------------------------------------------------- */
1966int create_tun_interface(char *name, int name_max_len, int *index, int flags, int ext_stats)
1967{
1968
1969	struct ctl_info kernctl_info;
1970	struct sockaddr_ctl kernctl_addr;
1971	u_int32_t optlen;
1972	int tunsock = -1;
1973
1974	tunsock = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
1975	if (tunsock == -1) {
1976		SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: cannot create kernel control socket (errno = %d)"), errno);
1977		goto fail;
1978	}
1979
1980	bzero(&kernctl_info, sizeof(kernctl_info));
1981    strlcpy(kernctl_info.ctl_name, UTUN_CONTROL_NAME, sizeof(kernctl_info.ctl_name));
1982	if (ioctl(tunsock, CTLIOCGINFO, &kernctl_info)) {
1983		SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: ioctl failed on kernel control socket (errno = %d)"), errno);
1984		goto fail;
1985	}
1986
1987	bzero(&kernctl_addr, sizeof(kernctl_addr)); // sets the sc_unit field to 0
1988	kernctl_addr.sc_len = sizeof(kernctl_addr);
1989	kernctl_addr.sc_family = AF_SYSTEM;
1990	kernctl_addr.ss_sysaddr = AF_SYS_CONTROL;
1991	kernctl_addr.sc_id = kernctl_info.ctl_id;
1992	kernctl_addr.sc_unit = 0; // we will get the unit number from getpeername
1993	if (connect(tunsock, (struct sockaddr *)&kernctl_addr, sizeof(kernctl_addr))) {
1994		SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: connect failed on kernel control socket (errno = %d)"), errno);
1995		goto fail;
1996	}
1997
1998	optlen = name_max_len;
1999	if (getsockopt(tunsock, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, name, &optlen)) {
2000		SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: getsockopt ifname failed on kernel control socket (errno = %d)"), errno);
2001		goto fail;
2002	}
2003
2004	*index = if_nametoindex(name);
2005
2006	if (flags) {
2007		int optflags = 0;
2008		optlen = sizeof(u_int32_t);
2009		if (getsockopt(tunsock, SYSPROTO_CONTROL, UTUN_OPT_FLAGS, &optflags, &optlen)) {
2010			SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: getsockopt flags failed on kernel control socket (errno = %d)"), errno);
2011			goto fail;
2012		}
2013
2014		optflags |= (UTUN_FLAGS_NO_INPUT + UTUN_FLAGS_NO_OUTPUT);
2015		optlen = sizeof(u_int32_t);
2016		if (setsockopt(tunsock, SYSPROTO_CONTROL, UTUN_OPT_FLAGS, &optflags, optlen)) {
2017			SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: setsockopt flags failed on kernel control socket (errno = %d)"), errno);
2018			goto fail;
2019		}
2020	}
2021
2022	if (ext_stats) {
2023		int optval = 1;
2024		if (setsockopt(tunsock, SYSPROTO_CONTROL, UTUN_OPT_EXT_IFDATA_STATS, &optval, sizeof(optval))) {
2025			SCLog(TRUE, LOG_ERR, CFSTR("create_tun_interface: setsockopt externat stats failed on kernel control socket (errno = %d)"), errno);
2026			goto fail;
2027		}
2028	}
2029
2030	return tunsock;
2031
2032fail:
2033	my_close(tunsock);
2034	return -1;
2035
2036}
2037
2038/* -----------------------------------------------------------------------------
2039 Set the delegate interface for the tun interface
2040 ----------------------------------------------------------------------------- */
2041int set_tun_delegate(int tunsock, char *delegate_ifname)
2042{
2043    int result = 0;
2044
2045    if ((result = setsockopt(tunsock, SYSPROTO_CONTROL, UTUN_OPT_SET_DELEGATE_INTERFACE, delegate_ifname, strlen(delegate_ifname))))
2046        SCLog(TRUE, LOG_ERR, CFSTR("set_tun_delegate: setsockopt delegate interface failed on kernel control socket (errno = %s)"), strerror(errno));
2047
2048    return result;
2049}
2050
2051/* -----------------------------------------------------------------------------
2052----------------------------------------------------------------------------- */
2053int event_create_socket(void * ctxt, int *eventfd, CFSocketRef *eventref, CFSocketCallBack callout, Boolean anysubclass)
2054{
2055    CFRunLoopSourceRef	rls;
2056    CFSocketContext	context = { 0, ctxt, NULL, NULL, NULL };
2057    struct kev_request	kev_req;
2058
2059	*eventfd = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
2060	if (*eventfd < 0) {
2061		SCLog(TRUE, LOG_ERR, CFSTR("event_create_socket cannot create event socket (errno = %d) "), errno);
2062		goto fail;
2063	}
2064
2065	kev_req.vendor_code = KEV_VENDOR_APPLE;
2066	kev_req.kev_class = KEV_NETWORK_CLASS;
2067	kev_req.kev_subclass = anysubclass ? KEV_ANY_SUBCLASS : KEV_INET_SUBCLASS;
2068	ioctl(*eventfd, SIOCSKEVFILT, &kev_req);
2069
2070    if ((*eventref = CFSocketCreateWithNative(NULL, *eventfd,
2071                    kCFSocketReadCallBack, callout, &context)) == 0) {
2072        goto fail;
2073    }
2074    if ((rls = CFSocketCreateRunLoopSource(NULL, *eventref, 0)) == 0)
2075        goto fail;
2076
2077    CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
2078    CFRelease(rls);
2079
2080    return 0;
2081
2082fail:
2083	if (*eventref) {
2084		CFSocketInvalidate(*eventref);
2085		CFRelease(*eventref);
2086	}
2087	else
2088		if (*eventfd >= 0) {
2089			close(*eventfd);
2090	}
2091	*eventref = 0;
2092	*eventfd = -1;
2093
2094    return -1;
2095}
2096
2097/* -----------------------------------------------------------------------------
2098 ----------------------------------------------------------------------------- */
2099typedef struct exec_callback_args {
2100	CFRunLoopRef            rl;
2101	CFRunLoopSourceRef      rls;
2102	CFRunLoopSourceContext  rlc;
2103	pid_t                   pid;
2104	int                     status;
2105	struct rusage	        rusage;
2106	SCDPluginExecCallBack   callback;
2107	void                   *callbackContext;
2108} exec_callback_args_t;
2109
2110/* -----------------------------------------------------------------------------
2111 ----------------------------------------------------------------------------- */
2112static
2113void exec_callback(pid_t pid, int status, struct rusage *rusage, void *context)
2114{
2115	if (isA_CFData(context)) {
2116		exec_callback_args_t *args = ALIGNED_CAST(__typeof__(args))CFDataGetMutableBytePtr((CFMutableDataRef)context);
2117		args->pid = pid;
2118		args->status = status;
2119		bcopy(rusage, &args->rusage, sizeof(args->rusage));
2120		// args->context already contains the service
2121		CFRunLoopSourceSignal(args->rls);
2122		CFRunLoopWakeUp(args->rl);
2123	}
2124}
2125
2126static void
2127SCNCPluginExecCallbackRunLoopSource (void *info)
2128{
2129	if (isA_CFData(info)) {
2130		exec_callback_args_t *args = ALIGNED_CAST(__typeof__(args))CFDataGetMutableBytePtr((CFMutableDataRef)info);
2131		if (args->callback) {
2132			args->callback(args->pid, args->status, &args->rusage, args->callbackContext);
2133		}
2134		CFRunLoopSourceInvalidate(args->rls);
2135		CFRelease(args->rls);
2136		CFRelease(args->rl);
2137		CFRelease((CFMutableDataRef)info); // release (was allocated in SCNCPluginExecCallbackRunLoopSourceInit)
2138	}
2139}
2140
2141CFMutableDataRef
2142SCNCPluginExecCallbackRunLoopSourceInit (CFRunLoopRef           runloop,
2143										 SCDPluginExecCallBack  callback,
2144										 void	               *callbackContext)
2145{
2146	CFMutableDataRef      dataRef; // to be used as SCNCPluginExecCallbackRunLoopSource's info
2147	UInt8                *dataPtr;
2148	exec_callback_args_t  args;
2149
2150	// create dataref and fill it with runloop args
2151	dataRef = CFDataCreateMutable(NULL, sizeof(args));
2152	if (dataRef == NULL) {
2153		return NULL;
2154	}
2155	CFDataSetLength(dataRef, sizeof(args));
2156	dataPtr = CFDataGetMutableBytePtr(dataRef);
2157
2158	bzero(&args, sizeof(args));
2159	args.rlc.info = dataRef; // use as SCNCPluginExecCallbackRunLoopSource's info
2160	args.rlc.perform = SCNCPluginExecCallbackRunLoopSource;
2161	args.rls = CFRunLoopSourceCreate(NULL, 0, &args.rlc);
2162	if (!args.rls){
2163		CFRelease(dataRef);
2164		return NULL;
2165	}
2166	args.callback = callback;
2167	args.callbackContext = callbackContext;
2168	if (!runloop) {
2169		args.rl = CFRunLoopGetCurrent();
2170	} else {
2171		args.rl = runloop;
2172	}
2173	CFRetain(args.rl);
2174	CFRunLoopAddSource(args.rl, args.rls, kCFRunLoopDefaultMode);
2175	bcopy(&args, dataPtr, sizeof(args));
2176	return dataRef; // to be used as exec_callback's context
2177}
2178
2179pid_t
2180SCNCPluginExecCommand (CFRunLoopRef           runloop,
2181					   SCDPluginExecCallBack  callback,
2182					   void        	         *callbackContext,
2183					   uid_t                  uid,
2184					   gid_t                  gid,
2185					   const char            *path,
2186					   char * const           argv[])
2187{
2188	pid_t            rc;
2189	CFMutableDataRef exec_callback_context;
2190
2191	exec_callback_context = SCNCPluginExecCallbackRunLoopSourceInit(runloop, callback, callbackContext);
2192	if (!exec_callback_context){
2193		SCLog(TRUE, LOG_ERR, CFSTR("SCNC: failed to initialize plugin exec_callback's runloop source"));
2194		return -1;
2195	}
2196
2197	rc = _SCDPluginExecCommand(exec_callback,
2198							   exec_callback_context,
2199							   uid,
2200							   gid,
2201							   path,
2202							   argv);
2203	return rc;
2204}
2205
2206pid_t
2207SCNCPluginExecCommand2 (CFRunLoopRef           runloop,
2208						SCDPluginExecCallBack  callback,
2209						void                  *callbackContext,
2210						uid_t                  uid,
2211						gid_t                  gid,
2212						const char            *path,
2213						char * const           argv[],
2214						SCDPluginExecSetup     setup,
2215						void                  *setupContext)
2216{
2217	pid_t            rc;
2218	CFMutableDataRef exec_callback_context;
2219
2220	exec_callback_context = SCNCPluginExecCallbackRunLoopSourceInit(runloop, callback, callbackContext);
2221	if (!exec_callback_context){
2222		SCLog(TRUE, LOG_ERR, CFSTR("SCNC: failed to initialize plugin exec_callback's runloop source"));
2223		return -1;
2224	}
2225
2226	rc = _SCDPluginExecCommand2(exec_callback,
2227								exec_callback_context,
2228								uid,
2229								gid,
2230								path,
2231								argv,
2232								setup,
2233								setupContext);
2234	return rc;
2235}
2236
2237#define SBSLAUNCHER_NAME "sbslauncher"
2238#define MAX_SBSLAUNCHER_ARGS 16
2239
2240/* Variable arguments are of type char*, and the last argument must be NULL */
2241pid_t
2242SCNCExecSBSLauncherCommandWithArguments (char *command,
2243										 SCDPluginExecSetup setup,
2244										 SCDPluginExecCallBack callback,
2245										 void *callbackContext,
2246										 ...)
2247{
2248	va_list			arguments;
2249	CFStringRef 	resourceDir = NULL;
2250	CFURLRef 		resourceURL = NULL, absoluteURL = NULL;
2251	char			thepath[MAXPATHLEN];
2252	pid_t			pid = 0;
2253	char 			*cmdarg[MAX_SBSLAUNCHER_ARGS];
2254
2255	resourceURL = CFBundleCopyResourcesDirectoryURL(gBundleRef);
2256
2257	if (resourceURL == NULL)
2258		goto done;
2259
2260	absoluteURL = CFURLCopyAbsoluteURL(resourceURL);
2261	if (absoluteURL == NULL)
2262		goto done;
2263
2264	resourceDir = CFURLCopyPath(absoluteURL);
2265	if (resourceDir == NULL)
2266		goto done;
2267
2268	if (!CFStringGetCString(resourceDir, thepath, sizeof(thepath), kCFStringEncodingMacRoman))
2269		goto done;
2270
2271	strlcat(thepath, SBSLAUNCHER_NAME, sizeof(thepath));
2272
2273	cmdarg[0] = SBSLAUNCHER_NAME;
2274	cmdarg[1] = command;
2275
2276	va_start(arguments, callbackContext);
2277	int i = 2;
2278
2279	char *arg_i = va_arg(arguments, char *);
2280	while (arg_i != NULL && i < (MAX_SBSLAUNCHER_ARGS - 1)) {
2281		cmdarg[i++] = arg_i;
2282		arg_i = va_arg(arguments, char *);
2283	}
2284	cmdarg[i] = NULL;
2285	va_end(arguments);
2286
2287	if (setup) {
2288		pid = SCNCPluginExecCommand2(NULL, callback, callbackContext, 0, 0, thepath, cmdarg, setup, callbackContext);
2289	} else {
2290		pid = SCNCPluginExecCommand(NULL, callback, callbackContext, 0, 0, thepath, cmdarg);
2291	}
2292
2293done:
2294	if (resourceDir)
2295		CFRelease(resourceDir);
2296	if (absoluteURL)
2297		CFRelease(absoluteURL);
2298	if (resourceURL)
2299		CFRelease(resourceURL);
2300
2301	return pid;
2302}
2303
2304void
2305extractEnvironmentVariablesApplierFunction (const void *key, const void *value, void *context)
2306{
2307	struct service *serv = (struct service *)context;
2308	CFRange range;
2309
2310	if (isA_CFString(key)) {
2311		char *key_buf = (char *)serv->envKeys[serv->envCount];
2312		char *value_buf = (char *)serv->envValues[serv->envCount];
2313
2314		key_buf[0] = '\0';
2315		range.location = 0;
2316		range.length = CFStringGetLength((CFStringRef)key);
2317		if (range.length <= 0 ||
2318			range.length >= sizeof(*serv->envKeys) ||
2319			CFStringGetBytes((CFStringRef)key, range, kCFStringEncodingUTF8, 0, false, (UInt8 *)key_buf, sizeof(*serv->envKeys), NULL) <= 0) {
2320			SCLog(TRUE, LOG_ERR, CFSTR("invalid EnvironmentVariables key %@, value %@"), key, value);
2321			return;
2322		}
2323		key_buf[range.length] = '\0';
2324		serv->envCount++;
2325
2326		value_buf[0] = '\0';
2327		if (isA_CFString(value)) {
2328			range.location = 0;
2329			range.length = CFStringGetLength((CFStringRef)value);
2330			if (range.length <= 0 ||
2331				range.length >= sizeof(*serv->envValues) ||
2332				CFStringGetBytes((CFStringRef)value, range, kCFStringEncodingUTF8, 0, false, (UInt8 *)value_buf, sizeof(*serv->envValues), NULL) <= 0) {
2333				SCLog(TRUE, LOG_ERR, CFSTR("invalid EnvironmentVariables key %@, value %@"), key, value);
2334				return;
2335			}
2336			value_buf[range.length] = '\0';
2337		} else if (isA_CFNumber(value)) {
2338			int64_t number = 0;
2339			if (CFNumberGetValue((CFNumberRef)value, kCFNumberSInt64Type, &number)) {
2340				snprintf(value_buf, sizeof(*serv->envValues), "%lld", number);
2341			} else {
2342				SCLog(TRUE, LOG_ERR, CFSTR("invalid EnvironmentVariables key %@, value %@"), key, value);
2343				return;
2344			}
2345		} else if (isA_CFBoolean(value)) {
2346			snprintf(value_buf, sizeof(*serv->envValues), "%s", CFBooleanGetValue((CFBooleanRef)value) ? "Yes" : "No");
2347		} else {
2348			SCLog(TRUE, LOG_ERR, CFSTR("invalid EnvironmentVariables key %@, value %@"), key, value);
2349			return;
2350		}
2351	} else {
2352		SCLog(TRUE, LOG_ERR, CFSTR("invalid EnvironmentVariables key"));
2353	}
2354}
2355
2356CFDictionaryRef
2357collectEnvironmentVariables (SCDynamicStoreRef storeRef, CFStringRef serviceID)
2358{
2359	if (!storeRef) {
2360		SCLog(TRUE, LOG_ERR, CFSTR("invalid DynamicStore passed to %s"), __FUNCTION__);
2361		return NULL;
2362	}
2363
2364	if (!serviceID) {
2365		SCLog(TRUE, LOG_ERR, CFSTR("invalid serviceID passed to %s"), __FUNCTION__);
2366		return NULL;
2367	}
2368
2369	return copyEntity(storeRef, kSCDynamicStoreDomainSetup, serviceID, CFSTR("EnvironmentVariables"));
2370}
2371
2372void
2373extractEnvironmentVariables (CFDictionaryRef envVarDict, struct service *serv)
2374{
2375	if (!envVarDict) {
2376		return;
2377	} else if (isA_CFDictionary(envVarDict) &&
2378			   CFDictionaryGetCount(envVarDict) > 0) {
2379		int count = CFDictionaryGetCount(envVarDict);
2380
2381		if (serv->envKeys) {
2382			free(serv->envKeys);
2383			serv->envKeys = NULL;
2384		}
2385		if (serv->envValues) {
2386			free(serv->envValues);
2387			serv->envValues = NULL;
2388		}
2389
2390		serv->envCount = 0;
2391		serv->envKeys = (char *)malloc(count * sizeof(envKeyValue_t));
2392		serv->envValues = (char *)malloc(count * sizeof(envKeyValue_t));
2393		if (!serv->envKeys || !serv->envValues) {
2394			SCLog(TRUE, LOG_ERR, CFSTR("Failed to allocate for environment variables"));
2395			return;
2396		}
2397
2398		CFDictionaryApplyFunction(envVarDict, extractEnvironmentVariablesApplierFunction, serv);
2399	} else {
2400		SCLog(TRUE, LOG_ERR, CFSTR("empty or invalid EnvironmentVariables dictionary"));
2401	}
2402}
2403
2404/*
2405 * Don't call SCLog() in this function as it's unsafe in a post-fork handler that requires async-signal safe.
2406 */
2407void
2408applyEnvironmentVariables (struct service *serv)
2409{
2410	int i;
2411
2412	for (i = 0; i < serv->envCount; i++) {
2413		if (serv->envKeys[i]) {
2414			unsetenv(serv->envKeys[i]);
2415			if (serv->envValues[i])
2416			    setenv(serv->envKeys[i], serv->envValues[i], TRUE);
2417		}
2418	}
2419
2420	serv->envCount = 0;
2421	if (serv->envKeys) {
2422		free(serv->envKeys);
2423		serv->envKeys = NULL;
2424	}
2425	if (serv->envValues) {
2426		free(serv->envValues);
2427		serv->envValues = NULL;
2428	}
2429
2430}
2431
2432const char *
2433scnc_get_reason_str(int scnc_reason)
2434{
2435	switch (scnc_reason) {
2436		case SCNC_STOP_CTRL_STOP:
2437			return scnc_ctrl_stopped;
2438		case SCNC_STOP_SYS_SLEEP:
2439			return scnc_sys_sleep;
2440		case SCNC_STOP_USER_LOGOUT:
2441			return scnc_usr_logout;
2442		case SCNC_STOP_USER_SWITCH:
2443			return scnc_usr_switch;
2444		case SCNC_STOP_SOCK_DISCONNECT:
2445		case SCNC_STOP_SOCK_DISCONNECT_NO_CLIENT:
2446			return scnc_sock_disco;
2447		case SCNC_STOP_PLUGIN_CHANGE:
2448			return scnc_plugin_chg;
2449		case SCNC_STOP_APP_REMOVED:
2450			return scnc_app_rem;
2451		case SCNC_STOP_USER_REQ:
2452		case SCNC_STOP_USER_REQ_NO_CLIENT:
2453			return scnc_usr_req;
2454		case SCNC_STOP_SERV_DISPOSE:
2455			return scnc_serv_disp;
2456		case SCNC_STOP_TERM_ALL:
2457			return scnc_term_all;
2458	}
2459	return CONSTSTR(NULL);
2460}
2461
2462const char *
2463ppp_error_to_string (u_int32_t native_ppp_error)
2464{
2465    switch (native_ppp_error) {
2466        case EXIT_FATAL_ERROR:
2467            return ppp_fatal;
2468        case EXIT_OPTION_ERROR:
2469            return ppp_option;
2470        case EXIT_NOT_ROOT:
2471            return ppp_not_root;
2472        case EXIT_NO_KERNEL_SUPPORT:
2473            return ppp_no_kern;
2474        case EXIT_USER_REQUEST:
2475            return ppp_user_req;
2476        case EXIT_LOCK_FAILED:
2477            return ppp_lock_fail;
2478        case EXIT_OPEN_FAILED:
2479            return ppp_open_fail;
2480        case EXIT_CONNECT_FAILED:
2481            return ppp_conn_fail;
2482        case EXIT_PTYCMD_FAILED:
2483            return ppp_pty_fail;
2484        case EXIT_NEGOTIATION_FAILED:
2485            return ppp_nego_fail;
2486        case EXIT_PEER_AUTH_FAILED:
2487            return ppp_peer_auth_fail;
2488        case EXIT_IDLE_TIMEOUT:
2489            return ppp_idle_tmo;
2490        case EXIT_CONNECT_TIME:
2491            return ppp_sess_tmo;
2492        case EXIT_CALLBACK:
2493            return ppp_callback;
2494        case EXIT_PEER_DEAD:
2495            return ppp_peer_dead;
2496        case EXIT_HANGUP:
2497            return ppp_disco_by_dev;
2498        case EXIT_LOOPBACK:
2499            return ppp_loopback;
2500        case EXIT_INIT_FAILED:
2501            return ppp_init_fail;
2502        case EXIT_AUTH_TOPEER_FAILED:
2503            return ppp_auth_fail;
2504        case EXIT_TERMINAL_FAILED:
2505            return ppp_term_fail;
2506        case EXIT_DEVICE_ERROR:
2507            return ppp_dev_err;
2508        case EXIT_PEER_NOT_AUTHORIZED:
2509            return ppp_peer_unauth;
2510        case EXIT_CNID_AUTH_FAILED:
2511            return ppp_cnid_auth_fail;
2512        case EXIT_PEER_UNREACHABLE:
2513            return ppp_peer_unreach;
2514    }
2515
2516    return CONSTSTR(NULL);
2517}
2518
2519const char *
2520ppp_dev_error_to_string (u_int16_t subtype, u_int32_t native_dev_error)
2521{
2522    // override with a more specific error
2523    if (native_dev_error) {
2524        switch (subtype) {
2525            case PPP_TYPE_L2TP:
2526                switch (native_dev_error) {
2527                    case EXIT_L2TP_NOSERVER:
2528                        return ppp_dev_no_srvr;
2529                    case EXIT_L2TP_NOANSWER:
2530                        return ppp_dev_no_ans;
2531                    case EXIT_L2TP_PROTOCOLERROR:
2532                        return ppp_dev_prot_err;
2533                    case EXIT_L2TP_NETWORKCHANGED:
2534                        return ppp_dev_net_chg;
2535                    case EXIT_L2TP_NOSHAREDSECRET:
2536                        return ppp_dev_psk;
2537                    case EXIT_L2TP_NOCERTIFICATE:
2538                        return ppp_dev_cert;
2539                }
2540                break;
2541
2542            case PPP_TYPE_PPTP:
2543                switch (native_dev_error) {
2544                    case EXIT_PPTP_NOSERVER:
2545                        return ppp_dev_no_srvr;
2546                    case EXIT_PPTP_NOANSWER:
2547                        return ppp_dev_no_ans;
2548                    case EXIT_PPTP_PROTOCOLERROR:
2549                        return ppp_dev_prot_err;
2550                    case EXIT_PPTP_NETWORKCHANGED:
2551                        return ppp_dev_net_chg;
2552                }
2553                break;
2554
2555            case PPP_TYPE_SERIAL:
2556                switch (native_dev_error) {
2557                    case EXIT_PPPSERIAL_NOCARRIER:
2558                        return ppp_dev_no_car;
2559                    case EXIT_PPPSERIAL_NONUMBER:
2560                        return ppp_dev_no_num;
2561                    case EXIT_PPPSERIAL_BADSCRIPT:
2562                        return ppp_dev_bad_script;
2563                    case EXIT_PPPSERIAL_BUSY:
2564                        return ppp_dev_busy;
2565                    case EXIT_PPPSERIAL_NODIALTONE:
2566                        return ppp_dev_no_dial;
2567                    case EXIT_PPPSERIAL_ERROR:
2568                        return ppp_dev_modem_err;
2569                    case EXIT_PPPSERIAL_NOANSWER:
2570                        return ppp_dev_no_ans;
2571                    case EXIT_PPPSERIAL_HANGUP:
2572                        return ppp_dev_hang;
2573                }
2574                break;
2575
2576            case PPP_TYPE_PPPoE:
2577                switch (native_dev_error) {
2578                    case EXIT_PPPoE_NOSERVER:
2579                        return ppp_dev_no_srvr;
2580                    case EXIT_PPPoE_NOSERVICE:
2581                        return ppp_dev_no_srvc;
2582                    case EXIT_PPPoE_NOAC:
2583                        return ppp_dev_no_ac;
2584                    case EXIT_PPPoE_NOACSERVICE:
2585                        return ppp_dev_no_ac_srvc;
2586                    case EXIT_PPPoE_CONNREFUSED:
2587                        return ppp_dev_conn_refuse;
2588                }
2589                break;
2590        }
2591    }
2592
2593    return CONSTSTR(NULL);
2594}
2595
2596const char *
2597ipsec_error_to_string (int status)
2598{
2599    switch (status) {
2600        case IPSEC_GENERIC_ERROR:
2601            return ipsec_gen_err;
2602        case IPSEC_NOSERVERADDRESS_ERROR:
2603            return ipsec_no_srvr_addr;
2604        case IPSEC_NOSHAREDSECRET_ERROR:
2605            return ipsec_no_psk;
2606        case IPSEC_NOCERTIFICATE_ERROR:
2607            return ipsec_no_cert;
2608        case IPSEC_RESOLVEADDRESS_ERROR:
2609            return ipsec_dns_err;
2610        case IPSEC_NOLOCALNETWORK_ERROR:
2611            return ipsec_no_local;
2612        case IPSEC_CONFIGURATION_ERROR:
2613            return ipsec_cfg_err;
2614        case IPSEC_RACOONCONTROL_ERROR:
2615            return ipsec_ctrl_err;
2616        case IPSEC_CONNECTION_ERROR:
2617            return ipsec_conn_err;
2618        case IPSEC_NEGOTIATION_ERROR:
2619            return ipsec_nego_err;
2620        case IPSEC_SHAREDSECRET_ERROR:
2621            return ipsec_psk_err;
2622        case IPSEC_SERVER_CERTIFICATE_ERROR:
2623            return ipsec_srvr_cert_err;
2624        case IPSEC_CLIENT_CERTIFICATE_ERROR:
2625            return ipsec_cli_cert_err;
2626        case IPSEC_XAUTH_ERROR:
2627            return ipsec_xauth_err;
2628        case IPSEC_NETWORKCHANGE_ERROR:
2629            return ipsec_net_chg;
2630        case IPSEC_PEERDISCONNECT_ERROR:
2631            return ipsec_peer_disco;
2632        case IPSEC_PEERDEADETECTION_ERROR:
2633            return ipsec_peer_dead;
2634        case IPSEC_EDGE_ACTIVATION_ERROR:
2635            return ipsec_edge_err;
2636        case IPSEC_IDLETIMEOUT_ERROR:
2637            return ipsec_idle_tmo;
2638        case IPSEC_CLIENT_CERTIFICATE_PREMATURE:
2639            return ipsec_cli_cert_pre;
2640        case IPSEC_CLIENT_CERTIFICATE_EXPIRED:
2641            return ipsec_cli_cert_exp;
2642        case IPSEC_SERVER_CERTIFICATE_PREMATURE:
2643            return ipsec_srvr_cert_pre;
2644        case IPSEC_SERVER_CERTIFICATE_EXPIRED:
2645            return ipsec_srvr_cert_exp;
2646        case IPSEC_SERVER_CERTIFICATE_INVALID_ID:
2647            return ipsec_srvr_cert_id;
2648    }
2649
2650    return CONSTSTR(NULL);
2651}
2652
2653const char *
2654vpn_error_to_string (u_int32_t status)
2655{
2656    switch (status) {
2657		case VPN_GENERIC_ERROR:
2658			return vpn_gen_err;
2659		case VPN_NOSERVERADDRESS_ERROR:
2660			return vpn_no_srvr_addr;
2661		case VPN_NOCERTIFICATE_ERROR:
2662			return vpn_no_cert;
2663		case VPN_RESOLVEADDRESS_ERROR:
2664			return vpn_dns_err;
2665		case VPN_NOLOCALNETWORK_ERROR:
2666			return vpn_no_local;
2667		case VPN_CONFIGURATION_ERROR:
2668			return vpn_cfg_err;
2669		case VPN_CONTROL_ERROR:
2670			return vpn_ctrl_err;
2671		case VPN_CONNECTION_ERROR:
2672			return vpn_conn_err;
2673		case VPN_NETWORKCHANGE_ERROR:
2674			return vpn_net_chg;
2675		case VPN_PEERDISCONNECT_ERROR:
2676			return vpn_peer_disco;
2677		case VPN_PEERDEADETECTION_ERROR:
2678			return vpn_peer_dead;
2679		case VPN_PEERNOTRESPONDING_ERROR:
2680			return vpn_peer_unresp;
2681		case VPN_NEGOTIATION_ERROR:
2682			return vpn_nego_err;
2683		case VPN_XAUTH_ERROR:
2684			return vpn_xauth_err;
2685		case VPN_EDGE_ACTIVATION_ERROR:
2686			return vpn_edge_err;
2687		case VPN_IDLETIMEOUT_ERROR:
2688			return vpn_idle_tmo;
2689		case VPN_ADDRESSINVALID_ERROR:
2690			return vpn_addr_invalid;
2691		case VPN_APPREQUIRED_ERROR:
2692			return vpn_ap_req;
2693		case VPN_CLIENT_CERTIFICATE_PREMATURE:
2694			return vpn_cli_cert_pre;
2695		case VPN_CLIENT_CERTIFICATE_EXPIRED:
2696			return vpn_cli_cert_exp;
2697		case VPN_SERVER_CERTIFICATE_PREMATURE:
2698			return vpn_srvr_cert_pre;
2699		case VPN_SERVER_CERTIFICATE_EXPIRED:
2700			return vpn_srvr_cert_exp;
2701		case VPN_SERVER_CERTIFICATE_INVALID_ID:
2702			return vpn_srvr_cert_id;
2703		case VPN_PLUGIN_UPDATE_REQUIRED:
2704			return vpn_plugin_upd;
2705		case VPN_PLUGIN_DISABLED:
2706			return vpn_plugin_dis;
2707	}
2708
2709    return CONSTSTR(NULL);
2710}
2711
2712/* -----------------------------------------------------------------------------
2713 cleanup dynamic store for serv->serviceID.
2714 ----------------------------------------------------------------------------- */
2715static void
2716removekeys( void *key, const void *value, void *context)
2717{
2718    Boolean ret;
2719
2720    ret = SCDynamicStoreRemoveValue((SCDynamicStoreRef)context, (CFStringRef)key);
2721    if (!ret)
2722        SCLog(TRUE, LOG_ERR, CFSTR("PPP Controller: removekeys SCDynamicStoreRemoveValue fails to remove key %@."), key);
2723}
2724
2725void
2726cleanup_dynamicstore(void *serv)
2727{
2728    CFDictionaryRef     entities = NULL;
2729    CFMutableArrayRef   patterns = NULL;
2730    CFStringRef         pattern = NULL;
2731
2732    /* clean up dynamic store */
2733    pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, ((struct service*)serv)->serviceID, kSCCompAnyRegex);
2734    if (pattern == NULL)
2735        return;
2736    patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2737    if (patterns == NULL)
2738        goto fail;
2739    CFArrayAppendValue(patterns, pattern);
2740    entities = SCDynamicStoreCopyMultiple(gDynamicStore, NULL, patterns);
2741    if (entities)
2742        CFDictionaryApplyFunction(entities, (CFDictionaryApplierFunction)removekeys, (void*)gDynamicStore);
2743
2744fail:
2745    my_CFRelease((void *)&pattern);
2746    my_CFRelease((void *)&patterns);
2747    my_CFRelease((void *)&entities);
2748}
2749
2750/* -----------------------------------------------------------------------------
2751 Pass in the optional exceptionServiceID to find the primary interface excluding
2752 the specified service; if the exceptionServiceID is primary, find the next active
2753 service interface based on NWI order.
2754
2755 If NULL is passed for exceptionServiceID, find the true primary interface.
2756 ----------------------------------------------------------------------------- */
2757CFStringRef copy_primary_interface_name(CFStringRef exceptionServiceID)
2758{
2759    CFStringRef		interfaceName = NULL, string = NULL, key = NULL, serviceID = NULL;
2760    CFDictionaryRef dict = NULL;
2761    Boolean			mustSearchNWIOrder = FALSE;
2762
2763    key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
2764    if (key) {
2765        dict = SCDynamicStoreCopyValue(gDynamicStore, key);
2766        CFRelease(key);
2767        if (isDictionary(dict)) {
2768            string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryInterface);
2769            if (isString(string)) {
2770                serviceID = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryService);
2771                if (serviceID && my_CFEqual(serviceID, exceptionServiceID)) {
2772                    mustSearchNWIOrder = TRUE;
2773                } else {
2774                    // The interface is not the exception, so allow
2775                    interfaceName = CFStringCreateCopy(NULL, string);
2776                }
2777            }
2778            CFRelease(dict);
2779        }
2780    }
2781
2782    if (interfaceName == NULL && mustSearchNWIOrder && exceptionServiceID != NULL) {
2783        CFStringRef exceptionInterfaceName = copy_interface_name(exceptionServiceID);
2784        nwi_state_t nwi_state = nwi_state_copy();
2785        if (exceptionInterfaceName && nwi_state) {
2786            for (nwi_ifstate_t interface = nwi_state_get_first_ifstate(nwi_state, AF_INET); interface != NULL; interface = nwi_ifstate_get_next(interface, AF_INET)) {
2787                char *nwi_interface_name = nwi_ifstate_get_ifname(interface);
2788                CFStringRef nwiInterfaceName = CFStringCreateWithCString(kCFAllocatorDefault, nwi_interface_name, kCFStringEncodingASCII);
2789                if (nwiInterfaceName && !my_CFEqual(nwiInterfaceName, exceptionInterfaceName)) {
2790                    nwi_ifstate_flags flags = nwi_ifstate_get_flags(interface);
2791                    if ((flags & NWI_IFSTATE_FLAGS_HAS_IPV4) && (flags & NWI_IFSTATE_FLAGS_HAS_DNS)) {
2792                        interfaceName = my_CFRetain(nwiInterfaceName);
2793                    }
2794                }
2795                my_CFRelease(&nwiInterfaceName);
2796
2797                // If we found the desired interface, exit now
2798                if (interfaceName != NULL) {
2799                    break;
2800                }
2801            }
2802        }
2803        my_CFRelease(&exceptionInterfaceName);
2804        nwi_state_release(nwi_state);
2805    }
2806
2807    return interfaceName;
2808}
2809
2810/* -----------------------------------------------------------------------------
2811 copy the string separatedy by / at index
2812 ----------------------------------------------------------------------------- */
2813static
2814CFStringRef copy_str_at_index(CFStringRef key, int index)
2815{
2816
2817    CFArrayRef	components;
2818    CFStringRef foundstr = NULL;
2819
2820    components = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
2821    if (CFArrayGetCount(components) == 5) {
2822        if ((foundstr = CFArrayGetValueAtIndex(components, index))){
2823            CFRetain(foundstr);
2824        }
2825    }
2826    CFRelease(components);
2827    return foundstr;
2828}
2829
2830/* -----------------------------------------------------------------------------
2831 ----------------------------------------------------------------------------- */
2832CFStringRef copy_service_id_for_interface(CFStringRef interfaceName)
2833{
2834    CFDictionaryRef     dict = NULL;
2835    CFStringRef         pattern = NULL;
2836    CFMutableArrayRef   patterns = NULL;
2837    CFStringRef         *keys = NULL;
2838    CFDictionaryRef     *values = NULL;
2839    CFIndex             count = 0;
2840    CFIndex             i = 0;
2841    CFStringRef         serviceID = NULL;
2842
2843    if (!isString(interfaceName)) {
2844        goto done;
2845    }
2846
2847    patterns = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
2848    pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault,
2849                                                          kSCDynamicStoreDomainState,
2850                                                          kSCCompAnyRegex,
2851                                                          kSCEntNetIPv4);
2852
2853    if (patterns == NULL || pattern == NULL)
2854        goto done;
2855    CFArrayAppendValue(patterns, pattern);
2856
2857    dict = SCDynamicStoreCopyMultiple(gDynamicStore, NULL, patterns);
2858    count = CFDictionaryGetCount(dict);
2859
2860    keys = calloc(count, sizeof(CFStringRef));
2861    values = calloc(count, sizeof(CFDictionaryRef));
2862    if (keys == NULL || values == NULL)
2863        goto done;
2864    CFDictionaryGetKeysAndValues(dict, (const void**)keys, (const void**)values);
2865
2866    for (i=0; i < count; i++) {
2867        CFDictionaryRef ipv4Dict = NULL;
2868        CFStringRef     ipv4Key = NULL;
2869
2870        ipv4Key  = keys[i];
2871        ipv4Dict = values[i];
2872
2873        if (!isString(ipv4Key) || !isDictionary(ipv4Dict)) {
2874            continue;
2875        }
2876
2877        /* Match interface name here */
2878        if (my_CFEqual(CFDictionaryGetValue(ipv4Dict, kSCPropInterfaceName), interfaceName)) {
2879            if ((CFStringHasPrefix(ipv4Key, kSCDynamicStoreDomainState)) && (CFStringHasSuffix(ipv4Key, kSCEntNetIPv4))) {
2880                /* Copy Service ID */
2881                serviceID = copy_str_at_index(ipv4Key, 3);
2882            }
2883            break;
2884        }
2885    }
2886
2887done:
2888    my_CFRelease(&pattern);
2889    my_CFRelease(&patterns);
2890    my_CFRelease(&dict);
2891    if (keys) {
2892        free(keys);
2893    }
2894    if (values) {
2895        free(values);
2896    }
2897
2898    return serviceID;
2899}
2900
2901/* -----------------------------------------------------------------------------
2902 ----------------------------------------------------------------------------- */
2903CFStringRef copy_interface_type(CFStringRef serviceID)
2904{
2905	CFDictionaryRef interface_dict = NULL;
2906	CFStringRef interface_key = NULL;
2907	CFStringRef hardware = NULL;
2908	CFStringRef interface_type = NULL;
2909
2910	if (!isString(serviceID)) {
2911		goto done;
2912	}
2913
2914	interface_key = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault,
2915                                                                kSCDynamicStoreDomainSetup,
2916                                                                serviceID,
2917                                                                kSCEntNetInterface);
2918
2919	interface_dict = SCDynamicStoreCopyValue(gDynamicStore, interface_key);
2920	if (!isDictionary(interface_dict)) {
2921		goto done;
2922	}
2923
2924	hardware = CFDictionaryGetValue(interface_dict, kSCPropNetInterfaceHardware);
2925
2926	if (isString(hardware)) {
2927        if (my_CFEqual(hardware, kSCEntNetAirPort)) {
2928            interface_type = CFRetain(kSCValNetVPNOnDemandRuleInterfaceTypeMatchWiFi);
2929        } else if (my_CFEqual(hardware, kSCEntNetEthernet)) {
2930            interface_type = CFRetain(kSCValNetVPNOnDemandRuleInterfaceTypeMatchEthernet);
2931        }
2932#if TARGET_OS_IPHONE
2933        else if (my_CFEqual(hardware, kSCEntNetCommCenter)) {
2934            interface_type = CFRetain(kSCValNetVPNOnDemandRuleInterfaceTypeMatchCellular);
2935        }
2936#endif
2937	}
2938
2939done:
2940    my_CFRelease(&interface_key);
2941    my_CFRelease(&interface_dict);
2942
2943	return interface_type;
2944}
2945
2946Boolean primary_interface_is_cellular(Boolean *hasPrimaryInterface)
2947{
2948    Boolean isCellular = FALSE;
2949#if TARGET_OS_IPHONE
2950	Boolean foundPrimaryInterface = FALSE;
2951	nwi_state_t state = nwi_state_copy();
2952	if (state != NULL) {
2953		int families[] = { AF_INET, AF_INET6 };
2954		for (uint32_t i = 0; !foundPrimaryInterface && (i < sizeof(families) / sizeof(families[0])); i++) {
2955			nwi_ifstate_t ifstate;
2956			for (ifstate = nwi_state_get_first_ifstate(state, families[i]);
2957				 ifstate != NULL;
2958				 ifstate = nwi_ifstate_get_next(ifstate, families[i]))
2959			{
2960				if (nwi_ifstate_get_vpn_server(ifstate) != NULL) {
2961					// Skip VPN interfaces
2962					continue;
2963				}
2964
2965				foundPrimaryInterface = TRUE;
2966				isCellular = nwi_ifstate_get_reachability_flags(ifstate) & kSCNetworkReachabilityFlagsIsWWAN;
2967				break;
2968			}
2969		}
2970		nwi_state_release(state);
2971	}
2972
2973    if (hasPrimaryInterface) {
2974        *hasPrimaryInterface = foundPrimaryInterface;
2975    }
2976#endif
2977	return isCellular;
2978}
2979
2980Boolean interface_is_cellular(const char *interface_name)
2981{
2982	Boolean isCellular = FALSE;
2983	if (interface_name == NULL) {
2984		return isCellular;
2985	}
2986
2987#if TARGET_OS_IPHONE
2988	nwi_state_t state = nwi_state_copy();
2989
2990	if (state != NULL) {
2991		nwi_ifstate_t ifstate = nwi_state_get_ifstate(state, interface_name);
2992		if (ifstate != NULL) {
2993			isCellular = ((nwi_ifstate_get_reachability_flags(ifstate) & kSCNetworkReachabilityFlagsIsWWAN) != 0);
2994		}
2995		nwi_state_release(state);
2996	}
2997#endif
2998
2999	return isCellular;
3000}
3001
3002/* -----------------------------------------------------------------------------
3003 ----------------------------------------------------------------------------- */
3004CFDictionaryRef copy_dns_dict(CFStringRef serviceID)
3005{
3006    CFStringRef     dnsKey = NULL;
3007    CFDictionaryRef dnsDict = NULL;
3008
3009    if (!isString(serviceID)) {
3010		goto done;
3011	}
3012
3013    dnsKey = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault,
3014                                                         kSCDynamicStoreDomainState,
3015                                                         serviceID,
3016                                                         kSCEntNetDNS);
3017    if (dnsKey == NULL) {
3018        goto done;
3019    }
3020
3021    dnsDict = SCDynamicStoreCopyValue(gDynamicStore, dnsKey);
3022    if (dnsDict == NULL) {
3023        goto done;
3024    }
3025
3026done:
3027	my_CFRelease(&dnsKey);
3028
3029	return dnsDict;
3030}
3031
3032/* -----------------------------------------------------------------------------
3033 ----------------------------------------------------------------------------- */
3034CFStringRef copy_interface_name(CFStringRef serviceID)
3035{
3036    CFStringRef		interfaceName = NULL;
3037    CFStringRef     ipv4Key = NULL;
3038    CFDictionaryRef ipv4Dict = NULL;
3039
3040    if (!isString(serviceID)) {
3041        goto done;
3042    }
3043
3044    ipv4Key = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault,
3045                                                         kSCDynamicStoreDomainState,
3046                                                         serviceID,
3047                                                         kSCEntNetIPv4);
3048    if (ipv4Key == NULL) {
3049        goto done;
3050    }
3051
3052    ipv4Dict = SCDynamicStoreCopyValue(gDynamicStore, ipv4Key);
3053    if (ipv4Dict == NULL) {
3054        goto done;
3055    }
3056
3057    interfaceName = CFDictionaryGetValue(ipv4Dict, kSCPropInterfaceName);
3058    if (interfaceName) {
3059        interfaceName = CFStringCreateCopy(kCFAllocatorDefault, interfaceName);
3060    }
3061
3062done:
3063    my_CFRelease(&ipv4Key);
3064    my_CFRelease(&ipv4Dict);
3065
3066    return interfaceName;
3067}
3068
3069/* -----------------------------------------------------------------------------
3070 ----------------------------------------------------------------------------- */
3071CFArrayRef
3072copy_service_order(void)
3073{
3074	CFDictionaryRef	ip_dict = NULL;
3075	CFStringRef		key;
3076	CFArrayRef		serviceorder = NULL;
3077
3078	key = CREATEGLOBALSETUP(kSCEntNetIPv4);
3079	if (key) {
3080		ip_dict = (CFDictionaryRef)SCDynamicStoreCopyValue(gDynamicStore, key);
3081		if (ip_dict) {
3082			serviceorder = CFDictionaryGetValue(ip_dict, kSCPropNetServiceOrder);
3083			if (serviceorder) {
3084				CFRetain(serviceorder);
3085			}
3086			CFRelease(ip_dict);
3087		}
3088		CFRelease(key);
3089	}
3090
3091	return serviceorder;
3092}
3093
3094CFStringRef scnc_copy_remote_server (struct service *serv, Boolean *isHostname)
3095{
3096	CFStringRef remote_address_key = NULL;
3097
3098	switch (serv->type) {
3099		case TYPE_PPP:
3100			remote_address_key = kSCPropNetPPPCommRemoteAddress;
3101			break;
3102		case TYPE_IPSEC:
3103			remote_address_key = kSCPropNetIPSecRemoteAddress;
3104			break;
3105		case TYPE_VPN:
3106			remote_address_key = kSCPropNetVPNRemoteAddress;
3107			break;
3108	}
3109
3110	if (isHostname)
3111	{
3112		*isHostname = FALSE;
3113	}
3114
3115	if (remote_address_key == NULL) {
3116		return NULL;
3117	}
3118
3119	CFStringRef remote_address = CFDictionaryGetValue(serv->systemprefs, remote_address_key);
3120	if (isA_CFString(remote_address) && CFStringGetLength(remote_address) > 0) {
3121		CFCharacterSetRef slash_set = CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault, CFSTR("/"));
3122		CFCharacterSetRef colon_set = CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault, CFSTR(":"));
3123		CFRange slash_range;
3124		CFRange colon_range;
3125
3126		CFRetain(remote_address);
3127
3128
3129		if (CFStringFindCharacterFromSet(remote_address,
3130		                                 slash_set,
3131		                                 CFRangeMake(0, CFStringGetLength(remote_address)),
3132		                                 0,
3133		                                 &slash_range))
3134		{
3135			CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, remote_address, NULL);
3136			if (url != NULL) {
3137				/* Check to see if there is a scheme on the URL. If not, add one. The hostname will not parse without a scheme */
3138				CFRange schemeRange = CFURLGetByteRangeForComponent(url, kCFURLComponentScheme, NULL);
3139				if (schemeRange.location == kCFNotFound) {
3140					CFRelease(url);
3141					CFStringRef address = CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("https://%@"), remote_address);
3142					url = CFURLCreateWithString(kCFAllocatorDefault, address, NULL);
3143					CFRelease(address);
3144				}
3145				if (url != NULL) {
3146					CFRelease(remote_address);
3147					remote_address = CFURLCopyHostName(url);
3148					CFRelease(url);
3149				}
3150			}
3151		} else if (CFStringFindCharacterFromSet(remote_address,
3152		                                        colon_set,
3153		                                        CFRangeMake(0, CFStringGetLength(remote_address)),
3154		                                        0,
3155		                                        &colon_range))
3156		{
3157			CFStringRef address = CFStringCreateWithSubstring(kCFAllocatorDefault,
3158															  remote_address,
3159															  CFRangeMake(0, colon_range.location));
3160			CFRelease(remote_address);
3161			remote_address = address;
3162		}
3163
3164		CFRelease(slash_set);
3165		CFRelease(colon_set);
3166
3167		if (remote_address == NULL) {
3168			return NULL;
3169		}
3170
3171		if (isHostname)
3172		{
3173			char *addr_cstr;
3174			CFIndex addr_cstr_len;
3175			struct sockaddr_storage sa_storage;
3176			memset(&sa_storage, 0, sizeof(sa_storage));
3177			addr_cstr_len = CFStringGetLength(remote_address); /* Assume that the address is ASCII */
3178			addr_cstr = CFAllocatorAllocate(kCFAllocatorDefault, addr_cstr_len + 1, 0);
3179
3180			CFStringGetCString(remote_address, addr_cstr, addr_cstr_len, kCFStringEncodingASCII);
3181
3182			if (inet_pton(AF_INET, addr_cstr, &((struct sockaddr_in *)&sa_storage)->sin_addr) == 1 ||
3183				inet_pton(AF_INET6, addr_cstr, &((struct sockaddr_in6 *)&sa_storage)->sin6_addr) == 1) {
3184				*isHostname = FALSE;
3185			} else {
3186				*isHostname = TRUE;
3187			}
3188
3189			CFAllocatorDeallocate(kCFAllocatorDefault, addr_cstr);
3190		}
3191	}
3192	return remote_address;
3193}
3194
3195void
3196scnc_log(int level, CFStringRef format, ...)
3197{
3198	if (ne_sm_bridge_is_logging_at_level(level)) {
3199		va_list args;
3200		va_start(args, format);
3201		if (!ne_sm_bridge_logv(level, format, args)) {
3202			SCLoggerVLog(NULL, level, format, args);
3203		}
3204		va_end(args);
3205	}
3206}
3207