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(struct remoteconf * rmconf,u_int8_t etype)420 check_etypeok( struct remoteconf *rmconf, u_int8_t etype)
421 {
422 	struct etypes *e;
423 
424 	for (e = rmconf->etypes; e != NULL; e = e->next) {
425 		if (e->type == etype)
426 			break;
427 	}
428 
429 	return e;
430 }
431 
432 /*%%%*/
433 struct isakmpsa *
newisakmpsa()434 newisakmpsa()
435 {
436 	struct isakmpsa *new;
437 
438 	new = racoon_calloc(1, sizeof(*new));
439 	if (new == NULL)
440 		return NULL;
441 
442 	/*
443 	 * Just for sanity, make sure this is initialized.  This is
444 	 * filled in for real when the ISAKMP proposal is configured.
445 	 */
446 	new->vendorid = VENDORID_UNKNOWN;
447 
448 	new->next = NULL;
449 	new->rmconf = NULL;
450 #ifdef HAVE_GSSAPI
451 	new->gssid = NULL;
452 #endif
453 
454 	return new;
455 }
456 
457 /*
458  * insert into tail of list.
459  */
460 void
insisakmpsa(new,rmconf)461 insisakmpsa(new, rmconf)
462 	struct isakmpsa *new;
463 	struct remoteconf *rmconf;
464 {
465 	struct isakmpsa *p;
466 
467 	new->rmconf = rmconf;
468 
469 	if (rmconf->proposal == NULL) {
470 		rmconf->proposal = new;
471 		return;
472 	}
473 
474 	for (p = rmconf->proposal; p->next != NULL; p = p->next)
475 		;
476 	p->next = new;
477 
478 	return;
479 }
480 
481 struct remoteconf *
foreachrmconf(rmconf_func_t rmconf_func,void * data)482 foreachrmconf(rmconf_func_t rmconf_func, void *data)
483 {
484   struct remoteconf *p, *ret = NULL;
485   RACOON_TAILQ_FOREACH_REVERSE(p, &rmtree, _rmtree, chain) {
486     ret = (*rmconf_func)(p, data);
487     if (ret)
488       break;
489   }
490 
491   return ret;
492 }
493 
494 static void *
dump_peers_identifiers(void * entry,void * arg)495 dump_peers_identifiers (void *entry, void *arg)
496 {
497 	struct idspec *id = (struct idspec*) entry;
498 	char buf[1024], *pbuf;
499 	pbuf = buf;
500 	pbuf += sprintf (pbuf, "\tpeers_identifier %s",
501 			 s_idtype (id->idtype));
502 	if (id->id)
503 		pbuf += sprintf (pbuf, " \"%s\"", id->id->v);
504 	plog(LLV_INFO, LOCATION, NULL, "%s;\n", buf);
505 	return NULL;
506 }
507 
508 static struct remoteconf *
dump_rmconf_single(struct remoteconf * p,void * data)509 dump_rmconf_single (struct remoteconf *p, void *data)
510 {
511 	struct etypes *etype = p->etypes;
512 	struct isakmpsa *prop = p->proposal;
513 	char buf[1024], *pbuf;
514 
515 	pbuf = buf;
516 	pbuf += sprintf(pbuf, "remote %s", saddr2str(p->remote));
517 	if (p->inherited_from)
518 		pbuf += sprintf(pbuf, " inherit %s",
519 				saddr2str(p->inherited_from->remote));
520 	plog(LLV_INFO, LOCATION, NULL, "%s {\n", buf);
521 	pbuf = buf;
522 	pbuf += sprintf(pbuf, "\texchange_type ");
523 	while (etype) {
524 		pbuf += sprintf (pbuf, "%s%s", s_etype(etype->type),
525 				 etype->next != NULL ? ", " : ";\n");
526 		etype = etype->next;
527 	}
528 	plog(LLV_INFO, LOCATION, NULL, "%s", buf);
529 	plog(LLV_INFO, LOCATION, NULL, "\tdoi %s;\n", s_doi(p->doitype));
530 	pbuf = buf;
531 	pbuf += sprintf(pbuf, "\tmy_identifier %s", s_idtype (p->idvtype));
532 	if (p->idvtype == IDTYPE_ASN1DN) {
533 		plog(LLV_INFO, LOCATION, NULL, "%s;\n", buf);
534 		plog(LLV_INFO, LOCATION, NULL, "\tcertificate_type %s \"%s\" \"%s\";\n",
535 			p->certtype == ISAKMP_CERT_X509SIGN ? "x509" : "*UNKNOWN*",
536 			p->mycertfile, p->myprivfile);
537 		switch (p->getcert_method) {
538 		  case 0:
539 		  	break;
540 		  case ISAKMP_GETCERT_PAYLOAD:
541 			plog(LLV_INFO, LOCATION, NULL, "\t/* peers certificate from payload */\n");
542 			break;
543 		  case ISAKMP_GETCERT_LOCALFILE:
544 			plog(LLV_INFO, LOCATION, NULL, "\tpeers_certfile \"%s\";\n", p->peerscertfile);
545 			break;
546 		  case ISAKMP_GETCERT_DNS:
547 			plog(LLV_INFO, LOCATION, NULL, "\tpeer_certfile dnssec;\n");
548 			break;
549 		  default:
550 			plog(LLV_INFO, LOCATION, NULL, "\tpeers_certfile *UNKNOWN* (%d)\n", p->getcert_method);
551 		}
552 	}
553 	else {
554 		if (p->idv)
555 			pbuf += sprintf (pbuf, " \"%s\"", p->idv->v);
556 		plog(LLV_INFO, LOCATION, NULL, "%s;\n", buf);
557 		genlist_foreach(p->idvl_p, &dump_peers_identifiers, NULL);
558 	}
559 
560 	plog(LLV_INFO, LOCATION, NULL, "\tsend_cert %s;\n",
561 		s_switch (p->send_cert));
562 	plog(LLV_INFO, LOCATION, NULL, "\tsend_cr %s;\n",
563 		s_switch (p->send_cr));
564 	plog(LLV_INFO, LOCATION, NULL, "\tverify_cert %s;\n",
565 		s_switch (p->verify_cert));
566 	plog(LLV_INFO, LOCATION, NULL, "\tverify_identifier %s;\n",
567 		s_switch (p->verify_identifier));
568 	plog(LLV_INFO, LOCATION, NULL, "\tnat_traversal %s;\n",
569 		p->nat_traversal == NATT_FORCE ?
570 			"force" : s_switch (p->nat_traversal));
571 	plog(LLV_INFO, LOCATION, NULL, "\tnonce_size %d;\n",
572 		p->nonce_size);
573 	plog(LLV_INFO, LOCATION, NULL, "\tpassive %s;\n",
574 		s_switch (p->passive));
575 	plog(LLV_INFO, LOCATION, NULL, "\tike_frag %s;\n",
576 		p->ike_frag == ISAKMP_FRAG_FORCE ?
577 			"force" : s_switch (p->ike_frag));
578 	plog(LLV_INFO, LOCATION, NULL, "\tesp_frag %d;\n", p->esp_frag);
579 	plog(LLV_INFO, LOCATION, NULL, "\tinitial_contact %s;\n",
580 		s_switch (p->ini_contact));
581 	plog(LLV_INFO, LOCATION, NULL, "\tgenerate_policy %s;\n",
582 		s_switch (p->gen_policy));
583 	plog(LLV_INFO, LOCATION, NULL, "\tsupport_proxy %s;\n",
584 		s_switch (p->support_proxy));
585 
586 	while (prop) {
587 		plog(LLV_INFO, LOCATION, NULL, "\n");
588 		plog(LLV_INFO, LOCATION, NULL,
589 			"\t/* prop_no=%d, trns_no=%d, rmconf=%s */\n",
590 			prop->prop_no, prop->trns_no,
591 			saddr2str(prop->rmconf->remote));
592 		plog(LLV_INFO, LOCATION, NULL, "\tproposal {\n");
593 		plog(LLV_INFO, LOCATION, NULL, "\t\tlifetime time %lu sec;\n",
594 			(long)prop->lifetime);
595 		plog(LLV_INFO, LOCATION, NULL, "\t\tlifetime bytes %zd;\n",
596 			prop->lifebyte);
597 		plog(LLV_INFO, LOCATION, NULL, "\t\tdh_group %s;\n",
598 			alg_oakley_dhdef_name(prop->dh_group));
599 		plog(LLV_INFO, LOCATION, NULL, "\t\tencryption_algorithm %s;\n",
600 			alg_oakley_encdef_name(prop->enctype));
601 		plog(LLV_INFO, LOCATION, NULL, "\t\thash_algorithm %s;\n",
602 			alg_oakley_hashdef_name(prop->hashtype));
603 		plog(LLV_INFO, LOCATION, NULL, "\t\tauthentication_method %s;\n",
604 			alg_oakley_authdef_name(prop->authmethod));
605 		plog(LLV_INFO, LOCATION, NULL, "\t}\n");
606 		prop = prop->next;
607 	}
608 	plog(LLV_INFO, LOCATION, NULL, "}\n");
609 	plog(LLV_INFO, LOCATION, NULL, "\n");
610 
611 	return NULL;
612 }
613 
614 void
dumprmconf()615 dumprmconf()
616 {
617 	foreachrmconf (dump_rmconf_single, NULL);
618 }
619 
620 struct idspec *
newidspec()621 newidspec()
622 {
623 	struct idspec *new;
624 
625 	new = racoon_calloc(1, sizeof(*new));
626 	if (new == NULL)
627 		return NULL;
628 	new->idtype = IDTYPE_ADDRESS;
629 
630 	return new;
631 }
632 
633 vchar_t *
script_path_add(path)634 script_path_add(path)
635 	vchar_t *path;
636 {
637 	char *script_dir;
638 	vchar_t *new_path;
639 	vchar_t *new_storage;
640 	vchar_t **sp;
641 	size_t len;
642 	size_t size;
643 
644 	script_dir = lcconf->pathinfo[LC_PATHTYPE_SCRIPT];
645 
646 	/* Try to find the script in the script directory */
647 	if ((path->v[0] != '/') && (script_dir != NULL)) {
648 		len = strlen(script_dir) + sizeof("/") + path->l + 1;
649 
650 		if ((new_path = vmalloc(len)) == NULL) {
651 			plog(LLV_ERROR, LOCATION, NULL,
652 			    "Cannot allocate memory: %s\n", strerror(errno));
653 			return NULL;
654 		}
655 
656 		new_path->v[0] = '\0';
657 		(void)strlcat(new_path->v, script_dir, len);
658 		(void)strlcat(new_path->v, "/", len);
659 		(void)strlcat(new_path->v, path->v, len);
660 
661 		vfree(path);
662 		path = new_path;
663 	}
664 
665 	return path;
666 }
667 
668 
669 struct isakmpsa *
dupisakmpsa(struct isakmpsa * sa)670 dupisakmpsa(struct isakmpsa *sa)
671 {
672 	struct isakmpsa *res=NULL;
673 
674 	if(sa == NULL)
675 		return NULL;
676 
677 	res=newisakmpsa();
678 	if(res == NULL)
679 		return NULL;
680 
681 	*res=*sa;
682 #ifdef HAVE_GSSAPI
683 	/* XXX gssid
684 	 */
685 #endif
686 	res->next=NULL;
687 
688 	if(sa->dhgrp != NULL)
689 		oakley_setdhgroup (sa->dh_group, &(res->dhgrp));
690 
691 	return res;
692 
693 }
694