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 <ctype.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
30#include <signal.h>
31#include <errno.h>
32#include <fcntl.h>
33#include <syslog.h>
34#include <netdb.h>
35#include <paths.h>
36#include <sys/queue.h>
37
38#include <sys/param.h>
39#include <sys/types.h>
40#include <sys/wait.h>
41#include <sys/time.h>
42#include <sys/resource.h>
43#include <sys/stat.h>
44#include <sys/socket.h>
45#include <netinet/in.h>
46#include <arpa/inet.h>
47#include <sys/sysctl.h>
48#include <pthread.h>
49#include <net/if.h>
50
51#include <CoreFoundation/CoreFoundation.h>
52#include <SystemConfiguration/SystemConfiguration.h>
53
54#include "vpnd.h"
55#include "cf_utils.h"
56#include "ipsec_utils.h"
57#include "vpnoptions.h"
58#include "vpnplugins.h"
59#include "RASSchemaDefinitions.h"
60
61extern int got_terminate(void);
62
63static int			secure_transport = 0;
64static int 			key_preference = -1;
65
66static CFMutableDictionaryRef		ipsec_conf = NULL;
67
68static struct vpn_params *current_params = 0;
69
70static pthread_t resolverthread = 0;
71static struct in_addr peer_address;
72static char remoteaddress[255];
73static int 	resolverfds[2];
74
75static int plugin_listen();
76static void plugin_close();
77static int plugin_get_args(struct vpn_params *params, int reload);
78
79//-----------------------------------------------------------------------------
80//	process_options
81//-----------------------------------------------------------------------------
82void ipsec_process_options(struct vpn_params *params)
83{
84
85}
86
87/* -----------------------------------------------------------------------------
88----------------------------------------------------------------------------- */
89void *ipsec_resolver_thread(void *arg)
90{
91    struct hostent 	*host;
92    char		result = -1;
93	int			count, fd;
94	u_int8_t	rd8;
95
96    if (pthread_detach(pthread_self()) == 0) {
97
98        // try to resolve the name
99        if ((host = gethostbyname(remoteaddress))) {
100
101			for (count = 0; host->h_addr_list[count]; count++);
102
103			rd8 = 0;
104			fd = open("/dev/random", O_RDONLY);
105			if (fd) {
106				read(fd, &rd8, sizeof(rd8));
107				close(fd);
108			}
109
110			if (count) {
111				peer_address = *(struct in_addr *)host->h_addr_list[rd8 % count];
112			} else {
113				bzero(&peer_address, sizeof(peer_address));
114			}
115            result = 0;
116        }
117    }
118
119    write(resolverfds[1], &result, 1);
120    return 0;
121}
122
123// ----------------------------------------------------------------------------
124//	process_prefs
125// ----------------------------------------------------------------------------
126int ipsec_process_prefs(struct vpn_params *params)
127{
128	char *errstr, c;
129	CFStringRef	string;
130
131	if (ipsec_conf) {
132		CFRelease(ipsec_conf);
133		ipsec_conf = NULL;
134	}
135
136	ipsec_conf = (CFMutableDictionaryRef)CFDictionaryGetValue(params->serverRef, kRASEntIPSec);
137	if (ipsec_conf == NULL) {
138		vpnlog(LOG_ERR, "IPSec plugin: IPSec dictionary not present\n");
139		goto fail;
140	}
141
142	ipsec_conf = CFDictionaryCreateMutableCopy(NULL, 0, ipsec_conf);
143
144	remoteaddress[0] = 0;
145	string  = CFDictionaryGetValue(ipsec_conf, kRASPropIPSecRemoteAddress);
146	if (isString(string))
147		CFStringGetCString(string, remoteaddress, sizeof(remoteaddress), kCFStringEncodingUTF8);
148
149	if (inet_aton(remoteaddress, &peer_address) == 0) {
150
151		if (pipe(resolverfds) < 0) {
152			vpnlog(LOG_ERR, "IPSec plugin: failed to create pipe for gethostbyname\n");
153			goto fail;
154		}
155
156		if (pthread_create(&resolverthread, NULL, ipsec_resolver_thread, NULL)) {
157			vpnlog(LOG_ERR, "IPSec plugin: failed to create thread for gethostbyname...\n");
158			close(resolverfds[0]);
159			close(resolverfds[1]);
160			goto fail;
161		}
162
163		while (read(resolverfds[0], &c, 1) != 1) {
164			if (got_terminate()) {
165				pthread_cancel(resolverthread);
166				break;
167			}
168		}
169
170		close(resolverfds[0]);
171		close(resolverfds[1]);
172
173		if (got_terminate())
174			goto fail;
175
176		if (c) {
177			vpnlog(LOG_ERR, "IPSec plugin: Host '%s' not found...\n", remoteaddress);
178			goto fail;
179		}
180
181		string = CFStringCreateWithCString(0, addr2ascii(AF_INET, &peer_address, sizeof(peer_address), 0), kCFStringEncodingASCII);
182		CFDictionarySetValue(ipsec_conf, kRASPropIPSecRemoteAddress, string);
183		CFRelease(string);
184	}
185
186	// verify the dictionary
187	if (IPSecValidateConfiguration(ipsec_conf, &errstr)) {
188
189		vpnlog(LOG_ERR, "IPSec plugin: Incorrect preferences (%s)\n", errstr);
190		goto fail;
191	}
192
193    return 0;
194
195fail:
196	if (ipsec_conf) {
197		CFRelease(ipsec_conf);
198		ipsec_conf = NULL;
199	}
200    return -1;
201}
202
203#if 0
204//-----------------------------------------------------------------------------
205//	convert a mask to a prefix
206//-----------------------------------------------------------------------------
207static int mask_to_prefix (in_addr_t mask)
208{
209	u_int32_t   prefix = 0;
210	int			i;
211
212#define IS_SET(field, bit)  (field & (1 << bit))
213
214	/* count the bits  set to 1 */
215	for (i = 31; i >= 0 && IS_SET(mask, i); i--)
216		prefix++;
217
218	/* verify the other bits are set to 0 */
219	for (; i >= 0 && !IS_SET(mask, i); i--);
220
221	/* check for incorrect prefix */
222	if (i >= 0)
223		return 0;
224
225	return prefix;
226}
227#endif
228
229//-----------------------------------------------------------------------------
230//	add_builtin_plugin for non plugin based connection
231//-----------------------------------------------------------------------------
232int ipsec_add_builtin_plugin(struct vpn_params* params, void *channel)
233{
234	struct vpn_channel *chan = (struct vpn_channel *)channel;
235
236    bzero(chan, sizeof(struct vpn_channel));
237    chan->get_pppd_args = plugin_get_args;
238    chan->listen = plugin_listen;
239    chan->close = plugin_close;
240
241    return 0;
242}
243
244/* -----------------------------------------------------------------------------
245    builtin ipsec get args: FIX ME
246----------------------------------------------------------------------------- */
247int plugin_get_args(struct vpn_params *params, int reload)
248{
249	current_params = params;
250	return 0;
251}
252
253//-----------------------------------------------------------------------------
254//	builtin ipsec listen
255//-----------------------------------------------------------------------------
256static int plugin_listen()
257{
258	int err;
259	char *errstr;
260
261     /* add security policies */
262	err = IPSecApplyConfiguration(ipsec_conf, &errstr);
263	if (err) {
264		vpnlog(LOG_ERR, "IPSec plugin: cannot configure racoon files (%s)...\n", errstr);
265		return -1;
266	}
267
268	err = IPSecInstallPolicies(ipsec_conf, -1, &errstr);
269	if (err) {
270		vpnlog(LOG_ERR, "IPSec plugin: cannot configure kernel policies (%s)...\n", errstr);
271		IPSecRemoveConfiguration(ipsec_conf, &errstr);
272		return -1;
273	}
274
275	/* set IPSec Key management to prefer most recent key */
276	if (IPSecSetSecurityAssociationsPreference(&key_preference, 0))
277		vpnlog(LOG_ERR, "IPSec plugin: cannot set IPSec Key management preference (error %d)\n", errno);
278
279
280	secure_transport = 1;
281
282    return 0;
283}
284
285//-----------------------------------------------------------------------------
286//	builtin ipsec close
287//-----------------------------------------------------------------------------
288static void plugin_close()
289{
290	int err;
291	char *errstr;
292
293    /* remove security policies */
294    if (secure_transport) {
295        err = IPSecRemoveConfiguration(ipsec_conf, &errstr);
296		if (err)
297			vpnlog(LOG_ERR, "IPSec plugin: cannot remove IPSec configuration (%s)...\n", errstr);
298        err = IPSecRemovePolicies(ipsec_conf, -1, &errstr);
299		if (err)
300			vpnlog(LOG_ERR, "IPSec plugin: cannot delete kernel policies (%s)...\n", errstr);
301		/* restore IPSec Key management preference */
302        if (IPSecSetSecurityAssociationsPreference(0, key_preference))
303            vpnlog(LOG_ERR, "L2TP plugin: cannot reset IPSec Key management preference (error %d)\n", errno);
304    }
305}
306
307