1 /*	$NetBSD: remoteconf.c,v 1.9.4.2 2008/06/18 07:30:19 mgrooms Exp $	*/
2 
3 /* Id: remoteconf.c,v 1.38 2006/05/06 15:52:44 manubsd Exp */
4 
5 /*
6  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the project nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "config.h"
35 
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/socket.h>
39 #include <sys/queue.h>
40 
41 #include <netinet/in.h>
42 #include <netinet/in_systm.h>
43 #include <netinet/ip.h>
44 
45 #include PATH_IPSEC_H
46 
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <errno.h>
51 
52 #include "var.h"
53 #include "misc.h"
54 #include "vmbuf.h"
55 #include "plog.h"
56 #include "sockmisc.h"
57 #include "genlist.h"
58 #include "debug.h"
59 
60 #include "isakmp_var.h"
61 #ifdef ENABLE_HYBRID
62 #include "isakmp_xauth.h"
63 #endif
64 #include "isakmp.h"
65 #include "ipsec_doi.h"
66 #include "oakley.h"
67 #include "remoteconf.h"
68 #include "localconf.h"
69 #include "grabmyaddr.h"
70 #include "policy.h"
71 #include "proposal.h"
72 #include "vendorid.h"
73 #include "gcmalloc.h"
74 #include "strnames.h"
75 #include "algorithm.h"
76 #include "nattraversal.h"
77 #include "isakmp_frag.h"
78 #include "genlist.h"
79 
TAILQ_HEAD(_rmtree,remoteconf)80 static TAILQ_HEAD(_rmtree, remoteconf) rmtree, rmtree_save, rmtree_tmp;
81 
82 /*
83  * Script hook names and script hook paths
84  */
85 char *script_names[SCRIPT_MAX + 1] = { "phase1_up", "phase1_down" };
86 
87 /*%%%*/
88 /*
89  * search remote configuration.
90  * don't use port number to search if its value is either IPSEC_PORT_ANY.
91  * If matching anonymous entry, then new entry is copied from anonymous entry.
92  * If no anonymous entry found, then return NULL.
93  * OUT:	NULL:	NG
94  *	Other:	remote configuration entry.
95  */
96 struct remoteconf *
getrmconf_strict(remote,allow_anon)97 getrmconf_strict(remote, allow_anon)
98 	struct sockaddr *remote;
99 	int allow_anon;
100 {
101 	struct remoteconf *p;
102 	struct remoteconf *anon = NULL;
103 	int withport;
104 	char buf[NI_MAXHOST + NI_MAXSERV + 10];
105 	char addr[NI_MAXHOST], port[NI_MAXSERV];
106 
107 	withport = 0;
108 
109 #ifndef ENABLE_NATT
110 	/*
111 	 * We never have ports set in our remote configurations, but when
112 	 * NAT-T is enabled, the kernel can have policies with ports and
113 	 * send us an acquire message for a destination that has a port set.
114 	 * If we do this port check here, we don't find the remote config.
115 	 *
116 	 * In an ideal world, we would be able to have remote conf with
117 	 * port, and the port could be a wildcard. That test could be used.
118 	 */
119 	if (remote->sa_family != AF_UNSPEC &&
120 	    extract_port(remote) != IPSEC_PORT_ANY)
121 		withport = 1;
122 #endif /* ENABLE_NATT */
123 
124 	if (remote->sa_family == AF_UNSPEC)
125 		snprintf (buf, sizeof(buf), "%s", "anonymous");
126 	else {
127 		GETNAMEINFO(remote, addr, port);
128 		snprintf(buf, sizeof(buf), "%s%s%s%s", addr,
129 			withport ? "[" : "",
130 			withport ? port : "",
131 			withport ? "]" : "");
132 	}
133 
134 	TAILQ_FOREACH(p, &rmtree, chain) {
135 		if ((remote->sa_family == AF_UNSPEC
136 		     && remote->sa_family == p->remote->sa_family)
137 		 || (!withport && cmpsaddrwop(remote, p->remote) == 0)
138 		 || (withport && cmpsaddrstrict(remote, p->remote) == 0)) {
139 			plog(LLV_DEBUG, LOCATION, NULL,
140 				"configuration found for %s.\n", buf);
141 			return p;
142 		}
143 
144 		/* save the pointer to the anonymous configuration */
145 		if (p->remote->sa_family == AF_UNSPEC)
146 			anon = p;
147 	}
148 
149 	if (allow_anon && anon != NULL) {
150 		plog(LLV_DEBUG, LOCATION, NULL,
151 			"anonymous configuration selected for %s.\n", buf);
152 		return anon;
153 	}
154 
155 	plog(LLV_DEBUG, LOCATION, NULL,
156 		"no remote configuration found.\n");
157 
158 	return NULL;
159 }
160 
161 struct remoteconf *
getrmconf(remote)162 getrmconf(remote)
163 	struct sockaddr *remote;
164 {
165 	return getrmconf_strict(remote, 1);
166 }
167 
168 struct remoteconf *
newrmconf()169 newrmconf()
170 {
171 	struct remoteconf *new;
172 	int i;
173 
174 	new = racoon_calloc(1, sizeof(*new));
175 	if (new == NULL)
176 		return NULL;
177 
178 	new->proposal = NULL;
179 
180 	/* set default */
181 	new->doitype = IPSEC_DOI;
182 	new->sittype = IPSECDOI_SIT_IDENTITY_ONLY;
183 	new->idvtype = IDTYPE_UNDEFINED;
184 	new->idvl_p = genlist_init();
185 	new->nonce_size = DEFAULT_NONCE_SIZE;
186 	new->passive = FALSE;
187 	new->ike_frag = FALSE;
188 	new->esp_frag = IP_MAXPACKET;
189 	new->ini_contact = TRUE;
190 	new->mode_cfg = FALSE;
191 	new->pcheck_level = PROP_CHECK_STRICT;
192 	new->verify_identifier = FALSE;
193 	new->verify_cert = TRUE;
194 	new->getcert_method = ISAKMP_GETCERT_PAYLOAD;
195 	new->getcacert_method = ISAKMP_GETCERT_LOCALFILE;
196 	new->cacerttype = ISAKMP_CERT_X509SIGN;
197 	new->certtype = ISAKMP_CERT_NONE;
198 	new->cacertfile = NULL;
199 	new->send_cert = TRUE;
200 	new->send_cr = TRUE;
201 	new->support_proxy = FALSE;
202 	for (i = 0; i <= SCRIPT_MAX; i++)
203 		new->script[i] = NULL;
204 	new->gen_policy = FALSE;
205 	new->retry_counter = lcconf->retry_counter;
206 	new->retry_interval = lcconf->retry_interval;
207 	new->nat_traversal = FALSE;
208 	new->rsa_private = genlist_init();
209 	new->rsa_public = genlist_init();
210 	new->idv = NULL;
211 	new->key = NULL;
212 
213 	new->dpd = TRUE; /* Enable DPD support by default */
214 	new->dpd_interval = 0; /* Disable DPD checks by default */
215 	new->dpd_retry = 5;
216 	new->dpd_maxfails = 5;
217 
218 	new->weak_phase1_check = 0;
219 
220 #ifdef ENABLE_HYBRID
221 	new->xauth = NULL;
222 #endif
223 
224 	return new;
225 }
226 
227 struct remoteconf *
copyrmconf(remote)228 copyrmconf(remote)
229 	struct sockaddr *remote;
230 {
231 	struct remoteconf *new, *old;
232 
233 	old = getrmconf_strict (remote, 0);
234 	if (old == NULL) {
235 		plog (LLV_ERROR, LOCATION, NULL,
236 		      "Remote configuration for '%s' not found!\n",
237 		      saddr2str (remote));
238 		return NULL;
239 	}
240 
241 	new = duprmconf (old);
242 
243 	return new;
244 }
245 
246 void *
dupidvl(entry,arg)247 dupidvl(entry, arg)
248 	void *entry;
249 	void *arg;
250 {
251 	struct idspec *id;
252 	struct idspec *old = (struct idspec *) entry;
253 	id = newidspec();
254 	if (!id) return (void *) -1;
255 
256 	if (set_identifier(&id->id, old->idtype, old->id) != 0) {
257 		racoon_free(id);
258 		return (void *) -1;
259 	}
260 
261 	id->idtype = old->idtype;
262 
263 	genlist_append(arg, id);
264 	return NULL;
265 }
266 
267 struct remoteconf *
duprmconf(rmconf)268 duprmconf (rmconf)
269 	struct remoteconf *rmconf;
270 {
271 	struct remoteconf *new;
272 
273 	new = racoon_calloc(1, sizeof(*new));
274 	if (new == NULL)
275 		return NULL;
276 	memcpy (new, rmconf, sizeof (*new));
277 	// FIXME: We should duplicate the proposal as well.
278 	// This is now handled in the cfparse.y
279 	// new->proposal = ...;
280 
281 	/* duplicate dynamic structures */
282 	if (new->etypes)
283 		new->etypes=dupetypes(new->etypes);
284 	new->idvl_p = genlist_init();
285 	genlist_foreach(rmconf->idvl_p, dupidvl, new->idvl_p);
286 
287 	return new;
288 }
289 
290 static void
idspec_free(void * data)291 idspec_free(void *data)
292 {
293 	vfree (((struct idspec *)data)->id);
294 	free (data);
295 }
296 
297 void
delrmconf(rmconf)298 delrmconf(rmconf)
299 	struct remoteconf *rmconf;
300 {
301 #ifdef ENABLE_HYBRID
302 	if (rmconf->xauth)
303 		xauth_rmconf_delete(&rmconf->xauth);
304 #endif
305 	if (rmconf->etypes){
306 		deletypes(rmconf->etypes);
307 		rmconf->etypes=NULL;
308 	}
309 	if (rmconf->idvl_p)
310 		genlist_free(rmconf->idvl_p, idspec_free);
311 	if (rmconf->dhgrp)
312 		oakley_dhgrp_free(rmconf->dhgrp);
313 	if (rmconf->proposal)
314 		delisakmpsa(rmconf->proposal);
315 	racoon_free(rmconf);
316 }
317 
318 void
delisakmpsa(sa)319 delisakmpsa(sa)
320 	struct isakmpsa *sa;
321 {
322 	if (sa->dhgrp)
323 		oakley_dhgrp_free(sa->dhgrp);
324 	if (sa->next)
325 		delisakmpsa(sa->next);
326 #ifdef HAVE_GSSAPI
327 	if (sa->gssid)
328 		vfree(sa->gssid);
329 #endif
330 	racoon_free(sa);
331 }
332 
333 struct etypes *
dupetypes(orig)334 dupetypes(orig)
335 	struct etypes *orig;
336 {
337 	struct etypes *new;
338 
339 	if (!orig)
340 		return NULL;
341 
342 	new = racoon_malloc(sizeof(struct etypes));
343 	if (new == NULL)
344 		return NULL;
345 
346 	new->type = orig->type;
347 	new->next = NULL;
348 
349 	if (orig->next)
350 		new->next=dupetypes(orig->next);
351 
352 	return new;
353 }
354 
355 void
deletypes(e)356 deletypes(e)
357 	struct etypes *e;
358 {
359 	if (e->next)
360 		deletypes(e->next);
361 	racoon_free(e);
362 }
363 
364 /*
365  * insert into head of list.
366  */
367 void
insrmconf(new)368 insrmconf(new)
369 	struct remoteconf *new;
370 {
371 	TAILQ_INSERT_HEAD(&rmtree, new, chain);
372 }
373 
374 void
remrmconf(rmconf)375 remrmconf(rmconf)
376 	struct remoteconf *rmconf;
377 {
378 	TAILQ_REMOVE(&rmtree, rmconf, chain);
379 }
380 
381 void
flushrmconf()382 flushrmconf()
383 {
384 	struct remoteconf *p, *next;
385 
386 	for (p = TAILQ_FIRST(&rmtree); p; p = next) {
387 		next = TAILQ_NEXT(p, chain);
388 		remrmconf(p);
389 		delrmconf(p);
390 	}
391 }
392 
393 void
initrmconf()394 initrmconf()
395 {
396 	TAILQ_INIT(&rmtree);
397 }
398 
399 void
save_rmconf()400 save_rmconf()
401 {
402 	rmtree_save=rmtree;
403 	initrmconf();
404 }
405 
406 void
save_rmconf_flush()407 save_rmconf_flush()
408 {
409 	rmtree_tmp=rmtree;
410 	rmtree=rmtree_save;
411 	flushrmconf();
412 	initrmconf();
413 	rmtree=rmtree_tmp;
414 }
415 
416 
417 
418 /* check exchange type to be acceptable */
419 struct etypes *
check_etypeok(rmconf,etype)420 check_etypeok(rmconf, etype)
421 	struct remoteconf *rmconf;
422 	u_int8_t etype;
423 {
424 	struct etypes *e;
425 
426 	for (e = rmconf->etypes; e != NULL; e = e->next) {
427 		if (e->type == etype)
428 			break;
429 	}
430 
431 	return e;
432 }
433 
434 /*%%%*/
435 struct isakmpsa *
newisakmpsa()436 newisakmpsa()
437 {
438 	struct isakmpsa *new;
439 
440 	new = racoon_calloc(1, sizeof(*new));
441 	if (new == NULL)
442 		return NULL;
443 
444 	/*
445 	 * Just for sanity, make sure this is initialized.  This is
446 	 * filled in for real when the ISAKMP proposal is configured.
447 	 */
448 	new->vendorid = VENDORID_UNKNOWN;
449 
450 	new->next = NULL;
451 	new->rmconf = NULL;
452 #ifdef HAVE_GSSAPI
453 	new->gssid = NULL;
454 #endif
455 
456 	return new;
457 }
458 
459 /*
460  * insert into tail of list.
461  */
462 void
insisakmpsa(new,rmconf)463 insisakmpsa(new, rmconf)
464 	struct isakmpsa *new;
465 	struct remoteconf *rmconf;
466 {
467 	struct isakmpsa *p;
468 
469 	new->rmconf = rmconf;
470 
471 	if (rmconf->proposal == NULL) {
472 		rmconf->proposal = new;
473 		return;
474 	}
475 
476 	for (p = rmconf->proposal; p->next != NULL; p = p->next)
477 		;
478 	p->next = new;
479 
480 	return;
481 }
482 
483 struct remoteconf *
foreachrmconf(rmconf_func_t rmconf_func,void * data)484 foreachrmconf(rmconf_func_t rmconf_func, void *data)
485 {
486   struct remoteconf *p, *ret = NULL;
487   RACOON_TAILQ_FOREACH_REVERSE(p, &rmtree, _rmtree, chain) {
488     ret = (*rmconf_func)(p, data);
489     if (ret)
490       break;
491   }
492 
493   return ret;
494 }
495 
496 static void *
dump_peers_identifiers(void * entry,void * arg)497 dump_peers_identifiers (void *entry, void *arg)
498 {
499 	struct idspec *id = (struct idspec*) entry;
500 	char buf[1024], *pbuf;
501 	pbuf = buf;
502 	pbuf += sprintf (pbuf, "\tpeers_identifier %s",
503 			 s_idtype (id->idtype));
504 	if (id->id)
505 		pbuf += sprintf (pbuf, " \"%s\"", id->id->v);
506 	plog(LLV_INFO, LOCATION, NULL, "%s;\n", buf);
507 	return NULL;
508 }
509 
510 static struct remoteconf *
dump_rmconf_single(struct remoteconf * p,void * data)511 dump_rmconf_single (struct remoteconf *p, void *data)
512 {
513 	struct etypes *etype = p->etypes;
514 	struct isakmpsa *prop = p->proposal;
515 	char buf[1024], *pbuf;
516 
517 	pbuf = buf;
518 	pbuf += sprintf(pbuf, "remote %s", saddr2str(p->remote));
519 	if (p->inherited_from)
520 		pbuf += sprintf(pbuf, " inherit %s",
521 				saddr2str(p->inherited_from->remote));
522 	plog(LLV_INFO, LOCATION, NULL, "%s {\n", buf);
523 	pbuf = buf;
524 	pbuf += sprintf(pbuf, "\texchange_type ");
525 	while (etype) {
526 		pbuf += sprintf (pbuf, "%s%s", s_etype(etype->type),
527 				 etype->next != NULL ? ", " : ";\n");
528 		etype = etype->next;
529 	}
530 	plog(LLV_INFO, LOCATION, NULL, "%s", buf);
531 	plog(LLV_INFO, LOCATION, NULL, "\tdoi %s;\n", s_doi(p->doitype));
532 	pbuf = buf;
533 	pbuf += sprintf(pbuf, "\tmy_identifier %s", s_idtype (p->idvtype));
534 	if (p->idvtype == IDTYPE_ASN1DN) {
535 		plog(LLV_INFO, LOCATION, NULL, "%s;\n", buf);
536 		plog(LLV_INFO, LOCATION, NULL, "\tcertificate_type %s \"%s\" \"%s\";\n",
537 			p->certtype == ISAKMP_CERT_X509SIGN ? "x509" : "*UNKNOWN*",
538 			p->mycertfile, p->myprivfile);
539 		switch (p->getcert_method) {
540 		  case 0:
541 		  	break;
542 		  case ISAKMP_GETCERT_PAYLOAD:
543 			plog(LLV_INFO, LOCATION, NULL, "\t/* peers certificate from payload */\n");
544 			break;
545 		  case ISAKMP_GETCERT_LOCALFILE:
546 			plog(LLV_INFO, LOCATION, NULL, "\tpeers_certfile \"%s\";\n", p->peerscertfile);
547 			break;
548 		  case ISAKMP_GETCERT_DNS:
549 			plog(LLV_INFO, LOCATION, NULL, "\tpeer_certfile dnssec;\n");
550 			break;
551 		  default:
552 			plog(LLV_INFO, LOCATION, NULL, "\tpeers_certfile *UNKNOWN* (%d)\n", p->getcert_method);
553 		}
554 	}
555 	else {
556 		if (p->idv)
557 			pbuf += sprintf (pbuf, " \"%s\"", p->idv->v);
558 		plog(LLV_INFO, LOCATION, NULL, "%s;\n", buf);
559 		genlist_foreach(p->idvl_p, &dump_peers_identifiers, NULL);
560 	}
561 
562 	plog(LLV_INFO, LOCATION, NULL, "\tsend_cert %s;\n",
563 		s_switch (p->send_cert));
564 	plog(LLV_INFO, LOCATION, NULL, "\tsend_cr %s;\n",
565 		s_switch (p->send_cr));
566 	plog(LLV_INFO, LOCATION, NULL, "\tverify_cert %s;\n",
567 		s_switch (p->verify_cert));
568 	plog(LLV_INFO, LOCATION, NULL, "\tverify_identifier %s;\n",
569 		s_switch (p->verify_identifier));
570 	plog(LLV_INFO, LOCATION, NULL, "\tnat_traversal %s;\n",
571 		p->nat_traversal == NATT_FORCE ?
572 			"force" : s_switch (p->nat_traversal));
573 	plog(LLV_INFO, LOCATION, NULL, "\tnonce_size %d;\n",
574 		p->nonce_size);
575 	plog(LLV_INFO, LOCATION, NULL, "\tpassive %s;\n",
576 		s_switch (p->passive));
577 	plog(LLV_INFO, LOCATION, NULL, "\tike_frag %s;\n",
578 		p->ike_frag == ISAKMP_FRAG_FORCE ?
579 			"force" : s_switch (p->ike_frag));
580 	plog(LLV_INFO, LOCATION, NULL, "\tesp_frag %d;\n", p->esp_frag);
581 	plog(LLV_INFO, LOCATION, NULL, "\tinitial_contact %s;\n",
582 		s_switch (p->ini_contact));
583 	plog(LLV_INFO, LOCATION, NULL, "\tgenerate_policy %s;\n",
584 		s_switch (p->gen_policy));
585 	plog(LLV_INFO, LOCATION, NULL, "\tsupport_proxy %s;\n",
586 		s_switch (p->support_proxy));
587 
588 	while (prop) {
589 		plog(LLV_INFO, LOCATION, NULL, "\n");
590 		plog(LLV_INFO, LOCATION, NULL,
591 			"\t/* prop_no=%d, trns_no=%d, rmconf=%s */\n",
592 			prop->prop_no, prop->trns_no,
593 			saddr2str(prop->rmconf->remote));
594 		plog(LLV_INFO, LOCATION, NULL, "\tproposal {\n");
595 		plog(LLV_INFO, LOCATION, NULL, "\t\tlifetime time %lu sec;\n",
596 			(long)prop->lifetime);
597 		plog(LLV_INFO, LOCATION, NULL, "\t\tlifetime bytes %zd;\n",
598 			prop->lifebyte);
599 		plog(LLV_INFO, LOCATION, NULL, "\t\tdh_group %s;\n",
600 			alg_oakley_dhdef_name(prop->dh_group));
601 		plog(LLV_INFO, LOCATION, NULL, "\t\tencryption_algorithm %s;\n",
602 			alg_oakley_encdef_name(prop->enctype));
603 		plog(LLV_INFO, LOCATION, NULL, "\t\thash_algorithm %s;\n",
604 			alg_oakley_hashdef_name(prop->hashtype));
605 		plog(LLV_INFO, LOCATION, NULL, "\t\tauthentication_method %s;\n",
606 			alg_oakley_authdef_name(prop->authmethod));
607 		plog(LLV_INFO, LOCATION, NULL, "\t}\n");
608 		prop = prop->next;
609 	}
610 	plog(LLV_INFO, LOCATION, NULL, "}\n");
611 	plog(LLV_INFO, LOCATION, NULL, "\n");
612 
613 	return NULL;
614 }
615 
616 void
dumprmconf()617 dumprmconf()
618 {
619 	foreachrmconf (dump_rmconf_single, NULL);
620 }
621 
622 struct idspec *
newidspec()623 newidspec()
624 {
625 	struct idspec *new;
626 
627 	new = racoon_calloc(1, sizeof(*new));
628 	if (new == NULL)
629 		return NULL;
630 	new->idtype = IDTYPE_ADDRESS;
631 
632 	return new;
633 }
634 
635 vchar_t *
script_path_add(path)636 script_path_add(path)
637 	vchar_t *path;
638 {
639 	char *script_dir;
640 	vchar_t *new_path;
641 	vchar_t *new_storage;
642 	vchar_t **sp;
643 	size_t len;
644 	size_t size;
645 
646 	script_dir = lcconf->pathinfo[LC_PATHTYPE_SCRIPT];
647 
648 	/* Try to find the script in the script directory */
649 	if ((path->v[0] != '/') && (script_dir != NULL)) {
650 		len = strlen(script_dir) + sizeof("/") + path->l + 1;
651 
652 		if ((new_path = vmalloc(len)) == NULL) {
653 			plog(LLV_ERROR, LOCATION, NULL,
654 			    "Cannot allocate memory: %s\n", strerror(errno));
655 			return NULL;
656 		}
657 
658 		new_path->v[0] = '\0';
659 		(void)strlcat(new_path->v, script_dir, len);
660 		(void)strlcat(new_path->v, "/", len);
661 		(void)strlcat(new_path->v, path->v, len);
662 
663 		vfree(path);
664 		path = new_path;
665 	}
666 
667 	return path;
668 }
669 
670 
671 struct isakmpsa *
dupisakmpsa(struct isakmpsa * sa)672 dupisakmpsa(struct isakmpsa *sa)
673 {
674 	struct isakmpsa *res=NULL;
675 
676 	if(sa == NULL)
677 		return NULL;
678 
679 	res=newisakmpsa();
680 	if(res == NULL)
681 		return NULL;
682 
683 	*res=*sa;
684 #ifdef HAVE_GSSAPI
685 	/* XXX gssid
686 	 */
687 #endif
688 	res->next=NULL;
689 
690 	if(sa->dhgrp != NULL)
691 		oakley_setdhgroup (sa->dh_group, &(res->dhgrp));
692 
693 	return res;
694 
695 }
696