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