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#include <stdio.h>
26#include <string.h>
27#include <stdlib.h>
28#include <unistd.h>
29#include <errno.h>
30#include <fcntl.h>
31#include <termios.h>
32#include <signal.h>
33#include <util.h>
34#include <sys/ioctl.h>
35#include <sys/types.h>
36#include <sys/socket.h>
37#include <sys/time.h>
38#include <sys/stat.h>
39#include <sys/param.h>
40#include <sys/wait.h>
41#include <net/if.h>
42#include <netinet/in.h>
43#include <net/if_types.h>
44#include <ifaddrs.h>
45#include <mach-o/dyld.h>
46#include <dirent.h>
47#include <NSSystemDirectories.h>
48#include <mach/mach_time.h>
49#include <SystemConfiguration/SystemConfiguration.h>
50#include <CoreFoundation/CFBundle.h>
51#include <ppp_defs.h>
52#include <ppp_domain.h>
53#include <ppp_msg.h>
54#include <ppp_privmsg.h>
55
56#include "vpnd.h"
57#include "vpnoptions.h"
58#include "cf_utils.h"
59#include "ipsec_utils.h"
60
61
62/* -----------------------------------------------------------------------------
63 Definitions
64----------------------------------------------------------------------------- */
65
66#define PPP_NKE_PATH 	"/System/Library/Extensions/PPP.kext"
67
68
69/* -----------------------------------------------------------------------------
70 Globals
71----------------------------------------------------------------------------- */
72
73bool	 		noload = 0;		/* don't load the kernel extension */
74
75
76
77
78/* -----------------------------------------------------------------------------
79----------------------------------------------------------------------------- */
80void closeall()
81{
82    int i;
83
84    for (i = getdtablesize() - 1; i >= 0; i--) close(i);
85    open("/dev/null", O_RDWR, 0);
86    dup(0);
87    dup(0);
88    return;
89}
90
91/* -----------------------------------------------------------------------------
92----------------------------------------------------------------------------- */
93u_long load_kext(char *kext, int byBundleID)
94{
95    int pid;
96
97    if ((pid = fork()) < 0)
98        return 1;
99
100    if (pid == 0) {
101        closeall();
102        // PPP kernel extension not loaded, try load it...
103		if (byBundleID)
104			execle("/sbin/kextload", "kextload", "-b", kext, (char *)0, (char *)0);
105		else
106			execle("/sbin/kextload", "kextload", kext, (char *)0, (char *)0);
107        exit(1);
108    }
109
110    while (waitpid(pid, 0, 0) < 0) {
111        if (errno == EINTR)
112            continue;
113       return 1;
114    }
115    return 0;
116}
117
118/* -----------------------------------------------------------------------------
119check if the kernel supports PPP
120----------------------------------------------------------------------------- */
121int ppp_available()
122{
123    int 	s;
124
125    // open to socket to the PF_PPP family
126    // if that works, the kernel extension is loaded.
127    if ((s = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL)) < 0) {
128
129#if !TARGET_OS_EMBEDDED // This file is not built for Embedded
130        if (!noload && !load_kext(PPP_NKE_PATH, 0))
131#else
132        if (!noload && !load_kext(PPP_NKE_ID, 1))
133#endif
134            s = socket(PF_PPP, SOCK_RAW, PPPPROTO_CTL);
135
136        if (s < 0)
137            return 0;
138    }
139
140    // could be smarter and get the version of the ppp family,
141    // using get option or ioctl
142
143    close(s);
144
145    return 1;
146}
147
148/* -----------------------------------------------------------------------------
149Copy the IPAddress of the default interface
150----------------------------------------------------------------------------- */
151CFStringRef CopyDefaultIPAddress()
152{
153    SCDynamicStoreRef 	store;
154    CFDictionaryRef	dict = 0;
155    CFStringRef		string, key;
156    CFArrayRef		array;
157
158    store = SCDynamicStoreCreate(0, CFSTR("vpnd"), 0, 0);
159    if (store == 0)
160        return 0;
161
162    key = SCDynamicStoreKeyCreateNetworkGlobalEntity(0, kSCDynamicStoreDomainState, kSCEntNetIPv4);
163    dict = SCDynamicStoreCopyValue(store, key);
164    CFRelease(key);
165
166    if (!isDictionary(dict))
167        goto error;
168
169    string = CFDictionaryGetValue(dict, kSCDynamicStorePropNetPrimaryService);
170    if (!isString(string))
171        goto error;
172
173    key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, string, kSCEntNetIPv4);
174    CFRelease(dict);
175    dict = SCDynamicStoreCopyValue(store, key);
176    CFRelease(key);
177
178    if (!isDictionary(dict))
179        goto error;
180
181    array = CFDictionaryGetValue(dict, kSCPropNetIPv4Addresses);
182    if (!isArray(array))
183        goto error;
184
185    string = CFArrayGetValueAtIndex(array, 0);
186    if (!isString(string))
187        goto error;
188
189    /* we got the address ! */
190    CFRetain(string);
191
192    CFRelease(dict);
193    CFRelease(store);
194    return string;
195
196error:
197    if (dict)
198        CFRelease(dict);
199    CFRelease(store);
200    return 0;
201}
202
203/* ----------------------------------------------------------------------------
204	find the interface that has address target_address assigned and return
205	the interface name and its primary_address
206	Return code:
207	0 if successful, -1 otherwise.
208 ---------------------------------------------------------------------------- */
209int get_interface(struct sockaddr_in *primary_address, const struct sockaddr_in *target_address, char *interface)
210{
211    struct ifaddrs *ifap = NULL;
212	int				ret = -1;
213
214
215	if (getifaddrs(&ifap) == 0) {
216		struct ifaddrs *ifa, *ifa1;
217		for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
218
219			if (ifa->ifa_name
220					&& ifa->ifa_addr
221					&& ifa->ifa_addr->sa_family == target_address->sin_family
222					&& ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == target_address->sin_addr.s_addr) {
223
224				strncpy(interface, ifa->ifa_name, IF_NAMESIZE);
225
226				if (primary_address) {
227					for (ifa1 = ifap; ifa1; ifa1 = ifa1->ifa_next) {
228
229						if (ifa1->ifa_name
230							&& !strncmp(ifa1->ifa_name, interface, IFNAMSIZ)
231							&& ifa1->ifa_addr
232							&& target_address
233							&& ifa1->ifa_addr->sa_family == target_address->sin_family) {
234
235							bcopy(ifa1->ifa_addr, primary_address, sizeof(*primary_address));
236							break;
237						}
238					}
239				}
240				ret = 0;
241				break;
242			}
243
244		}
245
246		freeifaddrs(ifap);
247	}
248
249	return ret;
250}
251
252/* ----------------------------------------------------------------------------
253	check if a given interface (or any if null) has the address assigned
254	Return code:
255	1 if address is found.
256 ---------------------------------------------------------------------------- */
257int find_address(const struct sockaddr_in *address, char *interface)
258{
259    struct ifaddrs *ifap = NULL;
260	int				found = 0;
261
262	if (getifaddrs(&ifap) == 0) {
263		struct ifaddrs *ifa;
264		for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
265
266			if (ifa->ifa_name
267					&& ifa->ifa_addr
268					&& (!interface || !strncmp(interface, ifa->ifa_name, IFNAMSIZ))
269					&& ifa->ifa_addr->sa_family == address->sin_family
270					&& ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr ==  address->sin_addr.s_addr) {
271
272				found = 1;
273				break;
274			}
275
276		}
277
278		freeifaddrs(ifap);
279	}
280
281	return found;
282}
283
284/* ----------------------------------------------------------------------------
285	get the address and return the interface name and main address of the interface
286	Return code:
287	0 if successful, -1 otherwise.
288 ---------------------------------------------------------------------------- */
289int get_route_interface(struct sockaddr *src, const struct sockaddr *dst, char *if_name)
290{
291	int				ret = -1;
292
293	// look if the cluster address is already assigned to an interface
294	if ((ret = get_interface((struct sockaddr_in *)src, (struct sockaddr_in *)dst, if_name))) {
295
296		// if not, then look ask the routing table for the interface to the cluster address is already assigned to an interface
297		ret = get_src_address(src, dst, NULL, if_name);
298
299	}
300
301	return ret;
302}
303
304
305// ----------------------------------------------------------------------------
306//	read function
307// ----------------------------------------------------------------------------
308int readn(int ref, void *data, int len)
309{
310    int 	n, left = len;
311    void 	*p = data;
312
313    while (left > 0) {
314        if ((n = read(ref, p, left)) < 0) {
315            if (errno != EINTR)
316                return -1;
317            n = 0;
318        }
319        else if (n == 0)
320            break; /* EOF */
321
322        left -= n;
323        p += n;
324    }
325    return (len - left);
326}
327
328// ----------------------------------------------------------------------------
329//	write function
330// ----------------------------------------------------------------------------
331int writen(int ref, void *data, int len)
332{
333    int 	n, left = len;
334    void 	*p = data;
335
336    while (left > 0) {
337        if ((n = write(ref, p, left)) <= 0) {
338            if (errno != EINTR)
339                return -1;
340            n = 0;
341        }
342        left -= n;
343        p += n;
344    }
345    return len;
346}
347
348