]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/vpn.c
ipsec-164.10.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / vpn.c
1 /*
2 * Copyright (c) 2007 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 /*
24 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
25 * All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. Neither the name of the project nor the names of its contributors
36 * may be used to endorse or promote products derived from this software
37 * without specific prior written permission.
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
40 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
43 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
44 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
45 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
48 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49 * SUCH DAMAGE.
50 */
51
52 #include "config.h"
53
54 #include <sys/types.h>
55 #include <sys/param.h>
56 #include <sys/socket.h>
57 #include <sys/signal.h>
58 #include <sys/stat.h>
59 #include <sys/un.h>
60
61 #include <System/net/pfkeyv2.h>
62
63 #include <netinet/in.h>
64 #ifndef HAVE_NETINET6_IPSEC
65 #include <netinet/ipsec.h>
66 #else
67 #include <netinet6/ipsec.h>
68 #endif
69
70
71 #include <stdlib.h>
72 #include <stdio.h>
73 #include <string.h>
74 #include <errno.h>
75 #include <netdb.h>
76 #ifdef HAVE_UNISTD_H
77 #include <unistd.h>
78 #endif
79 #ifdef ENABLE_HYBRID
80 #include <resolv.h>
81 #endif
82
83 #include "var.h"
84 #include "misc.h"
85 #include "vmbuf.h"
86 #include "plog.h"
87 #include "sockmisc.h"
88 #include "debug.h"
89 #include "handler.h"
90 #include "schedule.h"
91 #include "localconf.h"
92 #include "remoteconf.h"
93 #include "grabmyaddr.h"
94 #include "isakmp_var.h"
95 #include "isakmp.h"
96 #include "oakley.h"
97 #include "evt.h"
98 #include "pfkey.h"
99 #include "ipsec_doi.h"
100 #include "admin.h"
101 #include "admin_var.h"
102 #include "isakmp_inf.h"
103 #ifdef ENABLE_HYBRID
104 #include "isakmp_cfg.h"
105 #include "isakmp_unity.h"
106 #endif
107 #include "session.h"
108 #include "gcmalloc.h"
109 #include "sainfo.h"
110 #include "ipsec_doi.h"
111 #include "nattraversal.h"
112
113 #include "vpn_control.h"
114 #include "vpn_control_var.h"
115 #include "strnames.h"
116 #include "ike_session.h"
117 #include "ipsecMessageTracer.h"
118
119
120 static int vpn_get_ph2pfs(struct ph1handle *);
121
122 int
123 vpn_connect(struct bound_addr *srv, int oper)
124 {
125 int error = -1;
126 struct sockaddr_storage *dst;
127 struct remoteconf *rmconf;
128 struct sockaddr_storage *remote = NULL;
129 struct sockaddr_storage *local = NULL;
130 u_int16_t port;
131
132 dst = racoon_calloc(1, sizeof(struct sockaddr_storage)); // this should come from the bound_addr parameter
133 if (dst == NULL)
134 goto out;
135 ((struct sockaddr_in *)(dst))->sin_len = sizeof(struct sockaddr_in);
136 ((struct sockaddr_in *)(dst))->sin_family = AF_INET;
137 ((struct sockaddr_in *)(dst))->sin_port = 500;
138 ((struct sockaddr_in *)(dst))->sin_addr.s_addr = srv->address;
139
140 /*
141 * Find the source address
142 */
143 if ((local = getlocaladdr((struct sockaddr *)dst)) == NULL) {
144 plog(LLV_ERROR, LOCATION, NULL,
145 "cannot get local address\n");
146 goto out1;
147 }
148
149 /* find appropreate configuration */
150 rmconf = getrmconf(dst);
151 if (rmconf == NULL) {
152 plog(LLV_ERROR, LOCATION, NULL,
153 "no configuration found "
154 "for %s\n", saddrwop2str((struct sockaddr *)dst));
155 goto out1;
156 }
157
158 /* get remote IP address and port number. */
159 if ((remote = dupsaddr((struct sockaddr *)dst)) == NULL) {
160 plog(LLV_ERROR, LOCATION, NULL,
161 "failed to duplicate address\n");
162 goto out1;
163 }
164
165 switch (remote->ss_family) {
166 case AF_INET:
167 ((struct sockaddr_in *)remote)->sin_port =
168 ((struct sockaddr_in *)rmconf->remote)->sin_port;
169 break;
170 #ifdef INET6
171 case AF_INET6:
172 ((struct sockaddr_in6 *)remote)->sin6_port =
173 ((struct sockaddr_in6 *)rmconf->remote)->sin6_port;
174 break;
175 #endif
176 default:
177 plog(LLV_ERROR, LOCATION, NULL,
178 "invalid family: %d\n",
179 remote->ss_family);
180 goto out1;
181 break;
182 }
183
184 port = ntohs(getmyaddrsport(local));
185 if (set_port(local, port) == NULL)
186 goto out1;
187
188 plog(LLV_INFO, LOCATION, NULL,
189 "accept a request to establish IKE-SA: "
190 "%s\n", saddrwop2str((struct sockaddr *)remote));
191
192 IPSECLOGASLMSG("IPSec connecting to server %s\n",
193 saddrwop2str((struct sockaddr *)remote));
194
195 /* begin ident mode */
196 if (isakmp_ph1begin_i(rmconf, remote, local, oper) < 0)
197 goto out1;
198
199 error = 0;
200
201 out1:
202 if (dst != NULL)
203 racoon_free(dst);
204 if (local != NULL)
205 racoon_free(local);
206 if (remote != NULL)
207 racoon_free(remote);
208 out:
209
210 return error;
211 }
212
213 int
214 vpn_disconnect(struct bound_addr *srv, const char *reason)
215 {
216 union { // Wcast-align fix - force alignment
217 struct sockaddr_storage ss;
218 struct sockaddr_in saddr;
219 } u;
220
221 bzero(&u.saddr, sizeof(u.saddr));
222 u.saddr.sin_len = sizeof(u.saddr);
223 u.saddr.sin_addr.s_addr = srv->address;
224 u.saddr.sin_port = 0;
225 u.saddr.sin_family = AF_INET;
226
227 IPSECLOGASLMSG("IPSec disconnecting from server %s\n",
228 saddrwop2str((struct sockaddr *)&u.ss));
229
230 ike_sessions_stopped_by_controller(&u.ss,
231 0,
232 reason);
233 if (purgephXbydstaddrwop(&u.ss) > 0) {
234 return 0;
235 } else {
236 return -1;
237 }
238 }
239
240 int
241 vpn_start_ph2(struct bound_addr *addr, struct vpnctl_cmd_start_ph2 *pkt)
242 {
243 struct vpnctl_sa_selector *selector_ptr;
244 struct vpnctl_algo *algo_ptr, *next_algo;
245 int i, j, defklen;
246 struct sainfoalg *new_algo;
247 struct sainfo *new_sainfo = NULL, *check;
248 u_int16_t class, algorithm, keylen;
249 struct ph1handle *ph1;
250 struct sockaddr_in saddr;
251
252 struct id {
253 u_int8_t type; /* ID Type */
254 u_int8_t proto_id; /* Protocol ID */
255 u_int16_t port; /* Port */
256 u_int32_t addr; /* IPv4 address */
257 u_int32_t mask;
258 } *id_ptr;
259
260 /* verify ph1 exists */
261 bzero(&saddr, sizeof(saddr));
262 saddr.sin_len = sizeof(saddr);
263 saddr.sin_addr.s_addr = addr->address;
264 saddr.sin_port = 0;
265 saddr.sin_family = AF_INET;
266 ph1 = getph1bydstaddrwop((struct sockaddr_storage *)(&saddr));
267 if (ph1 == NULL) {
268 plog(LLV_ERROR, LOCATION, NULL,
269 "cannot start phase2 - no phase1 found.\n");
270 return -1;
271 }
272 if (ph1->status != PHASE1ST_ESTABLISHED) {
273 plog(LLV_ERROR, LOCATION, NULL,
274 "cannot start phase2 - phase1 not established.\n");
275 return -1;
276 }
277
278 selector_ptr = (struct vpnctl_sa_selector *)(pkt + 1);
279 algo_ptr = (struct vpnctl_algo *)(selector_ptr + ntohs(pkt->selector_count));
280
281 for (i = 0; i < ntohs(pkt->selector_count); i++, selector_ptr++) {
282 new_sainfo = newsainfo();
283 if (new_sainfo == NULL) {
284 plog(LLV_ERROR, LOCATION, NULL,
285 "unable to allocate sainfo struct.\n");
286 goto fail;
287 }
288
289 if (ntohl(selector_ptr->src_tunnel_mask) == 0xFFFFFFFF)
290 new_sainfo->idsrc = vmalloc(sizeof(struct id) - sizeof(u_int32_t));
291 else
292 new_sainfo->idsrc = vmalloc(sizeof(struct id));
293 if (new_sainfo->idsrc == NULL) {
294 plog(LLV_ERROR, LOCATION, NULL,
295 "unable to allocate id struct.\n");
296 goto fail;
297 }
298 if (selector_ptr->dst_tunnel_mask == 0xFFFFFFFF)
299 new_sainfo->iddst = vmalloc(sizeof(struct id) - sizeof(u_int32_t));
300 else
301 new_sainfo->iddst = vmalloc(sizeof(struct id));
302 if (new_sainfo->iddst == NULL) {
303 plog(LLV_ERROR, LOCATION, NULL,
304 "unable to allocate id struct.\n");
305 goto fail;
306 }
307
308 id_ptr = ALIGNED_CAST(struct id *)new_sainfo->idsrc->v;
309 if (ntohl(selector_ptr->src_tunnel_mask) == 0xFFFFFFFF)
310 id_ptr->type = IPSECDOI_ID_IPV4_ADDR;
311 else {
312 id_ptr->type = IPSECDOI_ID_IPV4_ADDR_SUBNET;
313 id_ptr->mask = selector_ptr->src_tunnel_mask;
314 }
315 id_ptr->addr = selector_ptr->src_tunnel_address;
316 id_ptr->port = selector_ptr->src_tunnel_port;
317 id_ptr->proto_id = selector_ptr->ul_protocol;
318
319 id_ptr = ALIGNED_CAST(struct id *)new_sainfo->iddst->v;
320 if (selector_ptr->dst_tunnel_mask == 0xFFFFFFFF)
321 id_ptr->type = IPSECDOI_ID_IPV4_ADDR;
322 else {
323 id_ptr->type = IPSECDOI_ID_IPV4_ADDR_SUBNET;
324 id_ptr->mask = selector_ptr->dst_tunnel_mask;
325 }
326 id_ptr->addr = selector_ptr->dst_tunnel_address;
327 id_ptr->port = selector_ptr->dst_tunnel_port;
328 id_ptr->proto_id = selector_ptr->ul_protocol;
329
330 new_sainfo->dynamic = addr->address;
331 new_sainfo->lifetime = ntohl(pkt->lifetime);
332
333 if (ntohs(pkt->pfs_group) != 0) {
334 new_sainfo->pfs_group = algtype2doi(algclass_isakmp_dh, ntohs(pkt->pfs_group));
335 if (new_sainfo->pfs_group == -1) {
336 plog(LLV_ERROR, LOCATION, NULL, "invalid dh group specified\n");
337 goto fail;
338 }
339 }
340 for (j = 0, next_algo = algo_ptr; j < ntohs(pkt->algo_count); j++, next_algo++) {
341
342 new_algo = newsainfoalg();
343 if (new_algo == NULL) {
344 plog(LLV_ERROR, LOCATION, NULL,
345 "failed to allocate algorithm structure\n");
346 goto fail;
347 }
348
349 class = ntohs(next_algo->algo_class);
350 algorithm = ntohs(next_algo->algo);
351 keylen = ntohs(next_algo->key_len);
352
353 new_algo->alg = algtype2doi(class, algorithm);
354 if (new_algo->alg == -1) {
355 plog(LLV_ERROR, LOCATION, NULL, "algorithm mismatched\n");
356 racoon_free(new_algo);
357 goto fail;
358 }
359
360 defklen = default_keylen(class, algorithm);
361 if (defklen == 0) {
362 if (keylen) {
363 plog(LLV_ERROR, LOCATION, NULL, "keylen not allowed\n");
364 racoon_free(new_algo);
365 goto fail;
366 }
367 } else {
368 if (keylen && check_keylen(class, algorithm, keylen) < 0) {
369 plog(LLV_ERROR, LOCATION, NULL, "invalid keylen %d\n", keylen);
370 racoon_free(new_algo);
371 goto fail;
372 }
373 }
374
375 if (keylen)
376 new_algo->encklen = keylen;
377 else
378 new_algo->encklen = defklen;
379
380 /* check if it's supported algorithm by kernel */
381 if (!(class == algclass_ipsec_auth && algorithm == algtype_non_auth)
382 && pk_checkalg(class, algorithm, new_algo->encklen)) {
383 int a = algclass2doi(class);
384 int b = new_algo->alg;
385 if (a == IPSECDOI_ATTR_AUTH)
386 a = IPSECDOI_PROTO_IPSEC_AH;
387 plog(LLV_ERROR, LOCATION, NULL,
388 "algorithm %s not supported by the kernel (missing module?)\n", s_ipsecdoi_trns(a, b));
389 racoon_free(new_algo);
390 goto fail;
391 }
392 inssainfoalg(&new_sainfo->algs[class], new_algo);
393 }
394
395 if (new_sainfo->algs[algclass_ipsec_enc] == 0) {
396 plog(LLV_ERROR, LOCATION, NULL,
397 "no encryption algorithm at %s\n", sainfo2str(new_sainfo));
398 goto fail;
399 }
400 if (new_sainfo->algs[algclass_ipsec_auth] == 0) {
401 plog(LLV_ERROR, LOCATION, NULL,
402 "no authentication algorithm at %s\n", sainfo2str(new_sainfo));
403 goto fail;
404 }
405 if (new_sainfo->algs[algclass_ipsec_comp] == 0) {
406 plog(LLV_ERROR, LOCATION, NULL,
407 "no compression algorithm at %s\n", sainfo2str(new_sainfo));
408 goto fail;
409 }
410
411 /* duplicate check */
412 check = getsainfo(new_sainfo->idsrc, new_sainfo->iddst, new_sainfo->id_i, 0);
413 if (check && (!check->idsrc && !new_sainfo->idsrc)) {
414 plog(LLV_ERROR, LOCATION, NULL,"duplicated sainfo: %s\n", sainfo2str(new_sainfo));
415 goto fail;
416 }
417 //plog(LLV_DEBUG2, LOCATION, NULL, "create sainfo: %s\n", sainfo2str(new_sainfo));
418 inssainfo(new_sainfo);
419 new_sainfo = NULL;
420 }
421
422 return 0;
423
424 fail:
425 if (new_sainfo)
426 delsainfo(new_sainfo);
427 flushsainfo_dynamic((u_int32_t)addr->address);
428 return -1;
429 }
430
431 static int
432 vpn_get_ph2pfs(struct ph1handle *ph1)
433 {
434 }
435
436
437 int
438 vpn_get_config(struct ph1handle *iph1, struct vpnctl_status_phase_change **msg, size_t *msg_size)
439 {
440
441 struct vpnctl_modecfg_params *params;
442 struct myaddrs *myaddr;
443 u_int16_t ifname_len, msize;
444 u_int8_t *cptr;
445
446 *msg = NULL;
447 msize = 0;
448
449 if (((struct sockaddr_in *)iph1->local)->sin_family != AF_INET) {
450 plog(LLV_ERROR, LOCATION, NULL,
451 "IPv6 not supported for mode config.\n");
452 return -1;
453 }
454
455 if (iph1->mode_cfg->attr_list == NULL)
456 return 1; /* haven't received configuration yet */
457
458 myaddr = find_myaddr((struct sockaddr *)iph1->local, 0);
459 if (myaddr == NULL) {
460 plog(LLV_ERROR, LOCATION, NULL,
461 "unable to find address structure.\n");
462 return -1;
463 }
464
465 msize = sizeof(struct vpnctl_status_phase_change)
466 + sizeof(struct vpnctl_modecfg_params);
467 msize += iph1->mode_cfg->attr_list->l;
468
469 *msg = racoon_calloc(1, msize);
470 if (*msg == NULL) {
471 plog(LLV_ERROR, LOCATION, NULL,
472 "faled to allocate space for message.\n");
473 return -1;
474 }
475
476 (*msg)->hdr.flags = htons(VPNCTL_FLAG_MODECFG_USED);
477 params = (struct vpnctl_modecfg_params *)(*msg + 1);
478 params->outer_local_addr = ((struct sockaddr_in *)iph1->local)->sin_addr.s_addr;
479 params->outer_remote_port = htons(0);
480 params->outer_local_port = htons(0);
481 ifname_len = strlen(myaddr->ifname);
482 memset(&params->ifname, 0, IFNAMSIZ);
483 memcpy(&params->ifname, myaddr->ifname, ifname_len < IFNAMSIZ ? ifname_len : IFNAMSIZ-1);
484 cptr = (u_int8_t *)(params + 1);
485 memcpy(cptr, iph1->mode_cfg->attr_list->v, iph1->mode_cfg->attr_list->l);
486 *msg_size = msize;
487
488 IPSECLOGASLMSG("IPSec Network Configuration established.\n");
489
490 return 0;
491 }
492
493
494 int
495 vpn_xauth_reply(u_int32_t address, void *attr_list, size_t attr_len)
496 {
497
498 struct isakmp_pl_attr *reply;
499 void* attr_ptr;
500 vchar_t *payload = NULL;
501 struct ph1handle *iph1;
502 struct sockaddr_in saddr;
503 int error = -1;
504 int tlen = attr_len;
505 struct isakmp_data *attr;
506 char *dataptr = (char *)attr_list;
507
508 /* find ph1 */
509 bzero(&saddr, sizeof(saddr));
510 saddr.sin_len = sizeof(saddr);
511 saddr.sin_addr.s_addr = address;
512 saddr.sin_port = 0;
513 saddr.sin_family = AF_INET;
514 iph1 = getph1bydstaddrwop((struct sockaddr_storage *)(&saddr));
515 if (iph1 == NULL) {
516 plog(LLV_ERROR, LOCATION, NULL,
517 "cannot reply to xauth request - no ph1 found.\n");
518 goto end;
519 }
520
521 if (iph1->xauth_awaiting_userinput == 0) {
522 plog(LLV_ERROR, LOCATION, NULL, "Huh? recvd xauth reply data with no xauth reply pending \n");
523 goto end;
524 }
525
526 /* validate attr lengths */
527 while (tlen > 0)
528 {
529 int tlv;
530
531 attr = (struct isakmp_data *)dataptr;
532 tlv = (attr->type & htons(0x8000)) == 0;
533
534 if (tlv) {
535 tlen -= ntohs(attr->lorv);
536 dataptr += ntohs(attr->lorv);
537 }
538 tlen -= sizeof(u_int32_t);
539 dataptr += sizeof(u_int32_t);
540 }
541 if (tlen != 0) {
542 plog(LLV_ERROR, LOCATION, NULL, "invalid auth info received from VPN Control socket.\n");
543 goto end;
544 }
545
546 payload = vmalloc(sizeof(struct isakmp_pl_attr) + attr_len);
547 if (payload == NULL) {
548 plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory for xauth reply\n");
549 goto end;
550 }
551 memset(payload->v, 0, sizeof(reply));
552
553 reply = (struct isakmp_pl_attr *)payload->v;
554 reply->h.len = htons(payload->l);
555 reply->type = ISAKMP_CFG_REPLY;
556 reply->id = iph1->pended_xauth_id; /* network byte order */
557 iph1->xauth_awaiting_userinput = 0; /* no longer waiting */
558 attr_ptr = reply + 1;
559 memcpy(attr_ptr, attr_list, attr_len);
560
561 plog(LLV_DEBUG, LOCATION, NULL,
562 "Sending MODE_CFG REPLY\n");
563 error = isakmp_cfg_send(iph1, payload,
564 ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 0, 0, iph1->xauth_awaiting_userinput_msg);
565 VPTRINIT(iph1->xauth_awaiting_userinput_msg);
566 ike_session_stop_xauth_timer(iph1);
567
568 IPSECLOGASLMSG("IPSec Extended Authentication sent.\n");
569
570 end:
571 if (payload)
572 vfree(payload);
573 return error;
574 }
575
576 int
577 vpn_assert(struct sockaddr_storage *src_addr, struct sockaddr_storage *dst_addr)
578 {
579 if (ike_session_assert(src_addr, dst_addr)) {
580 plog(LLV_ERROR, LOCATION, NULL,
581 "cannot assert - no matching session.\n");
582 return -1;
583 }
584
585 return 0;
586 }