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