]>
Commit | Line | Data |
---|---|---|
d1e348cf A |
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 | #ifdef __APPLE__ | |
62 | #include <System/net/pfkeyv2.h> | |
63 | #else | |
64 | #include <net/pfkeyv2.h> | |
65 | #endif | |
66 | ||
67 | #include <netinet/in.h> | |
68 | #ifndef HAVE_NETINET6_IPSEC | |
69 | #include <netinet/ipsec.h> | |
70 | #else | |
71 | #include <netinet6/ipsec.h> | |
72 | #endif | |
73 | ||
74 | ||
75 | #include <stdlib.h> | |
76 | #include <stdio.h> | |
77 | #include <string.h> | |
78 | #include <errno.h> | |
79 | #include <netdb.h> | |
80 | #ifdef HAVE_UNISTD_H | |
81 | #include <unistd.h> | |
82 | #endif | |
83 | #ifdef ENABLE_HYBRID | |
84 | #include <resolv.h> | |
85 | #endif | |
86 | ||
87 | #include "var.h" | |
88 | #include "misc.h" | |
89 | #include "vmbuf.h" | |
90 | #include "plog.h" | |
91 | #include "sockmisc.h" | |
92 | #include "debug.h" | |
93 | #include "handler.h" | |
94 | #include "schedule.h" | |
95 | #include "localconf.h" | |
96 | #include "remoteconf.h" | |
97 | #include "grabmyaddr.h" | |
98 | #include "isakmp_var.h" | |
99 | #include "isakmp.h" | |
100 | #include "oakley.h" | |
101 | #include "evt.h" | |
102 | #include "pfkey.h" | |
103 | #include "ipsec_doi.h" | |
104 | #include "admin.h" | |
105 | #include "admin_var.h" | |
106 | #include "isakmp_inf.h" | |
107 | #ifdef ENABLE_HYBRID | |
108 | #include "isakmp_cfg.h" | |
109 | #include "isakmp_unity.h" | |
110 | #endif | |
111 | #include "session.h" | |
112 | #include "gcmalloc.h" | |
113 | #include "sainfo.h" | |
114 | #include "ipsec_doi.h" | |
115 | #include "nattraversal.h" | |
116 | ||
117 | #include "vpn_control.h" | |
118 | #include "vpn_control_var.h" | |
119 | #include "strnames.h" | |
120 | #include "ike_session.h" | |
121 | ||
122 | ||
123 | static int vpn_get_ph2pfs(struct ph1handle *); | |
124 | ||
125 | int | |
126 | vpn_connect(struct bound_addr *srv) | |
127 | { | |
128 | int error = -1; | |
129 | struct sockaddr *dst; | |
130 | struct remoteconf *rmconf; | |
131 | struct sockaddr *remote = NULL; | |
132 | struct sockaddr *local = NULL; | |
133 | u_int16_t port; | |
134 | ||
135 | dst = racoon_calloc(1, sizeof(struct sockaddr)); // this should come from the bound_addr parameter | |
136 | if (dst == NULL) | |
137 | goto out; | |
138 | ((struct sockaddr_in *)(dst))->sin_len = sizeof(struct sockaddr_in); | |
139 | ((struct sockaddr_in *)(dst))->sin_family = AF_INET; | |
140 | ((struct sockaddr_in *)(dst))->sin_port = 500; | |
141 | ((struct sockaddr_in *)(dst))->sin_addr.s_addr = srv->address; | |
142 | ||
143 | /* | |
144 | * Find the source address | |
145 | */ | |
146 | if ((local = getlocaladdr(dst)) == NULL) { | |
147 | plog(LLV_ERROR, LOCATION, NULL, | |
148 | "cannot get local address\n"); | |
149 | goto out1; | |
150 | } | |
151 | ||
152 | /* find appropreate configuration */ | |
153 | rmconf = getrmconf(dst); | |
154 | if (rmconf == NULL) { | |
155 | plog(LLV_ERROR, LOCATION, NULL, | |
156 | "no configuration found " | |
157 | "for %s\n", saddrwop2str(dst)); | |
158 | goto out1; | |
159 | } | |
160 | ||
161 | /* get remote IP address and port number. */ | |
162 | if ((remote = dupsaddr(dst)) == NULL) { | |
163 | plog(LLV_ERROR, LOCATION, NULL, | |
164 | "failed to duplicate address\n"); | |
165 | goto out1; | |
166 | } | |
167 | ||
168 | switch (remote->sa_family) { | |
169 | case AF_INET: | |
170 | ((struct sockaddr_in *)remote)->sin_port = | |
171 | ((struct sockaddr_in *)rmconf->remote)->sin_port; | |
172 | break; | |
173 | #ifdef INET6 | |
174 | case AF_INET6: | |
175 | ((struct sockaddr_in6 *)remote)->sin6_port = | |
176 | ((struct sockaddr_in6 *)rmconf->remote)->sin6_port; | |
177 | break; | |
178 | #endif | |
179 | default: | |
180 | plog(LLV_ERROR, LOCATION, NULL, | |
181 | "invalid family: %d\n", | |
182 | remote->sa_family); | |
183 | goto out1; | |
184 | break; | |
185 | } | |
186 | ||
187 | port = ntohs(getmyaddrsport(local)); | |
188 | if (set_port(local, port) == NULL) | |
189 | goto out1; | |
190 | ||
191 | plog(LLV_INFO, LOCATION, NULL, | |
192 | "accept a request to establish IKE-SA: " | |
193 | "%s\n", saddrwop2str(remote)); | |
194 | ||
195 | /* begin ident mode */ | |
196 | if (isakmp_ph1begin_i(rmconf, remote, local, 1) < 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) | |
215 | { | |
216 | struct sockaddr_in saddr; | |
217 | ||
218 | bzero(&saddr, sizeof(saddr)); | |
219 | saddr.sin_len = sizeof(saddr); | |
220 | saddr.sin_addr.s_addr = srv->address; | |
221 | saddr.sin_port = 0; | |
222 | saddr.sin_family = AF_INET; | |
223 | ike_sessions_stopped_by_controller(&saddr, | |
224 | 0, | |
225 | ike_session_stopped_by_vpn_disconnect); | |
226 | if (purgephXbydstaddrwop((struct sockaddr *)(&saddr)) > 0) { | |
227 | return 0; | |
228 | } else { | |
229 | return -1; | |
230 | } | |
231 | } | |
232 | ||
233 | int | |
234 | vpn_start_ph2(struct bound_addr *addr, struct vpnctl_cmd_start_ph2 *pkt) | |
235 | { | |
236 | struct vpnctl_sa_selector *selector_ptr; | |
237 | struct vpnctl_algo *algo_ptr, *next_algo; | |
238 | int i, j, defklen; | |
239 | struct sainfoalg *new_algo; | |
240 | struct sainfo *new_sainfo = NULL, *check; | |
241 | u_int16_t class, algorithm, keylen; | |
242 | struct ph1handle *ph1; | |
243 | struct sockaddr_in saddr; | |
244 | ||
245 | struct id { | |
246 | u_int8_t type; /* ID Type */ | |
247 | u_int8_t proto_id; /* Protocol ID */ | |
248 | u_int16_t port; /* Port */ | |
249 | u_int32_t addr; /* IPv4 address */ | |
250 | u_int32_t mask; | |
251 | } *id_ptr; | |
252 | ||
253 | /* verify ph1 exists */ | |
254 | bzero(&saddr, sizeof(saddr)); | |
255 | saddr.sin_len = sizeof(saddr); | |
256 | saddr.sin_addr.s_addr = addr->address; | |
257 | saddr.sin_port = 0; | |
258 | saddr.sin_family = AF_INET; | |
259 | ph1 = getph1bydstaddrwop((struct sockaddr *)(&saddr)); | |
260 | if (ph1 == NULL) { | |
261 | plog(LLV_ERROR, LOCATION, NULL, | |
262 | "cannot start phase2 - no phase1 found.\n"); | |
263 | return -1; | |
264 | } | |
265 | if (ph1->status != PHASE1ST_ESTABLISHED) { | |
266 | plog(LLV_ERROR, LOCATION, NULL, | |
267 | "cannot start phase2 - phase1 not established.\n"); | |
268 | return -1; | |
269 | } | |
270 | ||
271 | selector_ptr = (struct vpnctl_sa_selector *)(pkt + 1); | |
272 | algo_ptr = (struct vpnctl_algo *)(selector_ptr + ntohs(pkt->selector_count)); | |
273 | ||
274 | for (i = 0; i < ntohs(pkt->selector_count); i++, selector_ptr++) { | |
275 | new_sainfo = newsainfo(); | |
276 | if (new_sainfo == NULL) { | |
277 | plog(LLV_ERROR, LOCATION, NULL, | |
278 | "unable to allocate sainfo struct.\n"); | |
279 | goto fail; | |
280 | } | |
281 | ||
282 | if (ntohl(selector_ptr->src_tunnel_mask) == 0xFFFFFFFF) | |
283 | new_sainfo->idsrc = vmalloc(sizeof(struct id) - sizeof(u_int32_t)); | |
284 | else | |
285 | new_sainfo->idsrc = vmalloc(sizeof(struct id)); | |
286 | if (new_sainfo->idsrc == NULL) { | |
287 | plog(LLV_ERROR, LOCATION, NULL, | |
288 | "unable to allocate id struct.\n"); | |
289 | goto fail; | |
290 | } | |
291 | if (selector_ptr->dst_tunnel_mask == 0xFFFFFFFF) | |
292 | new_sainfo->iddst = vmalloc(sizeof(struct id) - sizeof(u_int32_t)); | |
293 | else | |
294 | new_sainfo->iddst = vmalloc(sizeof(struct id)); | |
295 | if (new_sainfo->iddst == NULL) { | |
296 | plog(LLV_ERROR, LOCATION, NULL, | |
297 | "unable to allocate id struct.\n"); | |
298 | goto fail; | |
299 | } | |
300 | ||
301 | id_ptr = (struct id *)new_sainfo->idsrc->v; | |
302 | if (ntohl(selector_ptr->src_tunnel_mask) == 0xFFFFFFFF) | |
303 | id_ptr->type = IPSECDOI_ID_IPV4_ADDR; | |
304 | else { | |
305 | id_ptr->type = IPSECDOI_ID_IPV4_ADDR_SUBNET; | |
306 | id_ptr->mask = selector_ptr->src_tunnel_mask; | |
307 | } | |
308 | id_ptr->addr = selector_ptr->src_tunnel_address; | |
309 | id_ptr->port = selector_ptr->src_tunnel_port; | |
310 | id_ptr->proto_id = selector_ptr->ul_protocol; | |
311 | ||
312 | id_ptr = (struct id *)new_sainfo->iddst->v; | |
313 | if (selector_ptr->dst_tunnel_mask == 0xFFFFFFFF) | |
314 | id_ptr->type = IPSECDOI_ID_IPV4_ADDR; | |
315 | else { | |
316 | id_ptr->type = IPSECDOI_ID_IPV4_ADDR_SUBNET; | |
317 | id_ptr->mask = selector_ptr->dst_tunnel_mask; | |
318 | } | |
319 | id_ptr->addr = selector_ptr->dst_tunnel_address; | |
320 | id_ptr->port = selector_ptr->dst_tunnel_port; | |
321 | id_ptr->proto_id = selector_ptr->ul_protocol; | |
322 | ||
323 | new_sainfo->dynamic = addr->address; | |
324 | new_sainfo->lifetime = ntohl(pkt->lifetime); | |
325 | ||
326 | if (ntohs(pkt->pfs_group) != 0) { | |
327 | new_sainfo->pfs_group = algtype2doi(algclass_isakmp_dh, ntohs(pkt->pfs_group)); | |
328 | if (new_sainfo->pfs_group == -1) { | |
329 | plog(LLV_ERROR, LOCATION, NULL, "invalid dh group specified\n"); | |
330 | goto fail; | |
331 | } | |
332 | } | |
333 | for (j = 0, next_algo = algo_ptr; j < ntohs(pkt->algo_count); j++, next_algo++) { | |
334 | ||
335 | new_algo = newsainfoalg(); | |
336 | if (new_algo == NULL) { | |
337 | plog(LLV_ERROR, LOCATION, NULL, | |
338 | "failed to allocate algorithm structure\n"); | |
339 | goto fail; | |
340 | } | |
341 | ||
342 | class = ntohs(next_algo->algo_class); | |
343 | algorithm = ntohs(next_algo->algo); | |
344 | keylen = ntohs(next_algo->key_len); | |
345 | ||
346 | new_algo->alg = algtype2doi(class, algorithm); | |
347 | if (new_algo->alg == -1) { | |
348 | plog(LLV_ERROR, LOCATION, NULL, "algorithm mismatched\n"); | |
349 | racoon_free(new_algo); | |
350 | goto fail; | |
351 | } | |
352 | ||
353 | defklen = default_keylen(class, algorithm); | |
354 | if (defklen == 0) { | |
355 | if (keylen) { | |
356 | plog(LLV_ERROR, LOCATION, NULL, "keylen not allowed\n"); | |
357 | racoon_free(new_algo); | |
358 | goto fail; | |
359 | } | |
360 | } else { | |
361 | if (keylen && check_keylen(class, algorithm, keylen) < 0) { | |
362 | plog(LLV_ERROR, LOCATION, NULL, "invalid keylen %d\n", keylen); | |
363 | racoon_free(new_algo); | |
364 | goto fail; | |
365 | } | |
366 | } | |
367 | ||
368 | if (keylen) | |
369 | new_algo->encklen = keylen; | |
370 | else | |
371 | new_algo->encklen = defklen; | |
372 | ||
373 | /* check if it's supported algorithm by kernel */ | |
374 | if (!(class == algclass_ipsec_auth && algorithm == algtype_non_auth) | |
375 | && pk_checkalg(class, algorithm, new_algo->encklen)) { | |
376 | int a = algclass2doi(class); | |
377 | int b = new_algo->alg; | |
378 | if (a == IPSECDOI_ATTR_AUTH) | |
379 | a = IPSECDOI_PROTO_IPSEC_AH; | |
380 | plog(LLV_ERROR, LOCATION, NULL, | |
381 | "algorithm %s not supported by the kernel (missing module?)\n", s_ipsecdoi_trns(a, b)); | |
382 | racoon_free(new_algo); | |
383 | goto fail; | |
384 | } | |
385 | inssainfoalg(&new_sainfo->algs[class], new_algo); | |
386 | } | |
387 | ||
388 | if (new_sainfo->algs[algclass_ipsec_enc] == 0) { | |
389 | plog(LLV_ERROR, LOCATION, NULL, | |
390 | "no encryption algorithm at %s\n", sainfo2str(new_sainfo)); | |
391 | goto fail; | |
392 | } | |
393 | if (new_sainfo->algs[algclass_ipsec_auth] == 0) { | |
394 | plog(LLV_ERROR, LOCATION, NULL, | |
395 | "no authentication algorithm at %s\n", sainfo2str(new_sainfo)); | |
396 | goto fail; | |
397 | } | |
398 | if (new_sainfo->algs[algclass_ipsec_comp] == 0) { | |
399 | plog(LLV_ERROR, LOCATION, NULL, | |
400 | "no compression algorithm at %s\n", sainfo2str(new_sainfo)); | |
401 | goto fail; | |
402 | } | |
403 | ||
404 | /* duplicate check */ | |
405 | check = getsainfo(new_sainfo->idsrc, new_sainfo->iddst, new_sainfo->id_i, 0); | |
406 | if (check && (!check->idsrc && !new_sainfo->idsrc)) { | |
407 | plog(LLV_ERROR, LOCATION, NULL,"duplicated sainfo: %s\n", sainfo2str(new_sainfo)); | |
408 | goto fail; | |
409 | } | |
410 | plog(LLV_DEBUG2, LOCATION, NULL, "create sainfo: %s\n", sainfo2str(new_sainfo)); | |
411 | inssainfo(new_sainfo); | |
412 | new_sainfo = NULL; | |
413 | } | |
414 | ||
415 | return 0; | |
416 | ||
417 | fail: | |
418 | if (new_sainfo) | |
419 | delsainfo(new_sainfo); | |
420 | flushsainfo_dynamic(addr); | |
421 | return -1; | |
422 | } | |
423 | ||
424 | static int | |
425 | vpn_get_ph2pfs(struct ph1handle *ph1) | |
426 | { | |
427 | } | |
428 | ||
429 | ||
430 | int | |
431 | vpn_get_config(struct ph1handle *iph1, struct vpnctl_status_phase_change **msg, size_t *msg_size) | |
432 | { | |
433 | ||
434 | struct vpnctl_modecfg_params *params; | |
435 | struct myaddrs *myaddr; | |
436 | u_int16_t ifname_len, msize; | |
437 | u_int8_t *cptr; | |
438 | ||
439 | *msg = NULL; | |
440 | msize = 0; | |
441 | ||
442 | if (((struct sockaddr_in *)iph1->local)->sin_family != AF_INET) { | |
443 | plog(LLV_ERROR, LOCATION, NULL, | |
444 | "IPv6 not supported for mode config.\n"); | |
445 | return -1; | |
446 | } | |
447 | ||
448 | if (iph1->mode_cfg->attr_list == NULL) | |
449 | return 1; /* haven't received configuration yet */ | |
450 | ||
451 | myaddr = find_myaddr(iph1->local, 0); | |
452 | if (myaddr == NULL) { | |
453 | plog(LLV_ERROR, LOCATION, NULL, | |
454 | "unable to find address structure.\n"); | |
455 | return -1; | |
456 | } | |
457 | ||
458 | msize = sizeof(struct vpnctl_status_phase_change) | |
459 | + sizeof(struct vpnctl_modecfg_params); | |
460 | msize += iph1->mode_cfg->attr_list->l; | |
461 | ||
462 | *msg = racoon_calloc(1, msize); | |
463 | if (*msg == NULL) { | |
464 | plog(LLV_ERROR, LOCATION, NULL, | |
465 | "faled to allocate space for message.\n"); | |
466 | return -1; | |
467 | } | |
468 | ||
469 | (*msg)->hdr.flags = htons(VPNCTL_FLAG_MODECFG_USED); | |
470 | params = (struct vpnctl_modecfg_params *)(*msg + 1); | |
471 | params->outer_local_addr = ((struct sockaddr_in *)iph1->local)->sin_addr.s_addr; | |
472 | params->outer_remote_port = htons(0); | |
473 | params->outer_local_port = htons(0); | |
474 | ifname_len = strlen(myaddr->ifname); | |
475 | memset(¶ms->ifname, 0, IFNAMSIZ); | |
476 | memcpy(¶ms->ifname, myaddr->ifname, ifname_len < IFNAMSIZ ? ifname_len : IFNAMSIZ-1); | |
477 | cptr = (u_int8_t *)(params + 1); | |
478 | memcpy(cptr, iph1->mode_cfg->attr_list->v, iph1->mode_cfg->attr_list->l); | |
479 | *msg_size = msize; | |
480 | ||
481 | return 0; | |
482 | } | |
483 | ||
484 | ||
485 | int | |
486 | vpn_xauth_reply(u_int32_t address, void *attr_list, size_t attr_len) | |
487 | { | |
488 | ||
489 | struct isakmp_pl_attr *reply; | |
490 | void* attr_ptr; | |
491 | vchar_t *payload = NULL; | |
492 | struct ph1handle *iph1; | |
493 | struct sockaddr_in saddr; | |
494 | int error = -1; | |
495 | int tlen = attr_len; | |
496 | struct isakmp_data *attr; | |
497 | char *dataptr = (char *)attr_list; | |
498 | ||
499 | /* find ph1 */ | |
500 | bzero(&saddr, sizeof(saddr)); | |
501 | saddr.sin_len = sizeof(saddr); | |
502 | saddr.sin_addr.s_addr = address; | |
503 | saddr.sin_port = 0; | |
504 | saddr.sin_family = AF_INET; | |
505 | iph1 = getph1bydstaddrwop((struct sockaddr *)(&saddr)); | |
506 | if (iph1 == NULL) { | |
507 | plog(LLV_ERROR, LOCATION, NULL, | |
508 | "cannot reply to xauth request - no ph1 found.\n"); | |
509 | goto end; | |
510 | } | |
511 | ||
512 | if (iph1->xauth_awaiting_userinput == 0) { | |
513 | plog(LLV_ERROR, LOCATION, NULL, "Huh? recvd xauth reply data with no xauth reply pending \n"); | |
514 | goto end; | |
515 | } | |
516 | ||
517 | /* validate attr lengths */ | |
518 | while (tlen > 0) | |
519 | { | |
520 | int tlv; | |
521 | ||
522 | attr = (struct isakmp_data *)dataptr; | |
523 | tlv = (attr->type & htons(0x8000)) == 0; | |
524 | ||
525 | if (tlv) { | |
526 | tlen -= ntohs(attr->lorv); | |
527 | dataptr += ntohs(attr->lorv); | |
528 | } | |
529 | tlen -= sizeof(u_int32_t); | |
530 | dataptr += sizeof(u_int32_t); | |
531 | } | |
532 | if (tlen != 0) { | |
533 | plog(LLV_ERROR, LOCATION, NULL, "invalid auth info received from VPN Control socket.\n"); | |
534 | goto end; | |
535 | } | |
536 | ||
537 | payload = vmalloc(sizeof(struct isakmp_pl_attr) + attr_len); | |
538 | if (payload == NULL) { | |
539 | plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory for xauth reply\n"); | |
540 | goto end; | |
541 | } | |
542 | memset(payload->v, 0, sizeof(reply)); | |
543 | ||
544 | reply = (struct isakmp_pl_attr *)payload->v; | |
545 | reply->h.len = htons(payload->l); | |
546 | reply->type = ISAKMP_CFG_REPLY; | |
547 | reply->id = iph1->pended_xauth_id; /* network byte order */ | |
548 | iph1->xauth_awaiting_userinput = 0; /* no longer waiting */ | |
549 | attr_ptr = reply + 1; | |
550 | memcpy(attr_ptr, attr_list, attr_len); | |
551 | ||
552 | plog(LLV_DEBUG, LOCATION, NULL, | |
553 | "Sending MODE_CFG REPLY\n"); | |
554 | error = isakmp_cfg_send(iph1, payload, | |
555 | ISAKMP_NPTYPE_ATTR, ISAKMP_FLAG_E, 0, 0, iph1->xauth_awaiting_userinput_msg); | |
556 | VPTRINIT(iph1->xauth_awaiting_userinput_msg); | |
557 | ike_session_stop_xauth_timer(iph1); | |
558 | ||
559 | end: | |
560 | if (payload) | |
561 | vfree(payload); | |
562 | return error; | |
563 | } | |
564 |