eb26e56a1ebe5b1854f13c1c5df51f944af98f63
[bcm963xx.git] / userapps / opensource / ipsec-tools / src / racoon / remoteconf.c
1 /* $Id: remoteconf.c,v 1.24 2004/12/01 10:59:41 vanhu Exp $ */
2
3 /*
4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5  * All rights reserved.
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  * 
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include "config.h"
33
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/socket.h>
37 #include <sys/queue.h>
38
39 #include <netinet/in.h>
40
41 #ifndef HAVE_NETINET6_IPSEC
42 #include <netinet/ipsec.h>
43 #else
44 #include <netinet6/ipsec.h>
45 #endif
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 #include "isakmp.h"
62 #include "ipsec_doi.h"
63 #include "oakley.h"
64 #include "remoteconf.h"
65 #include "localconf.h"
66 #include "grabmyaddr.h"
67 #include "proposal.h"
68 #include "vendorid.h"
69 #include "gcmalloc.h"
70 #include "strnames.h"
71 #include "algorithm.h"
72 #include "nattraversal.h"
73 #include "genlist.h"
74
75 static TAILQ_HEAD(_rmtree, remoteconf) rmtree;
76
77 /* 
78  * Script hook names
79  */
80 char *script_names[SCRIPT_MAX + 1] = { "phase1_up", "phase1_down" };
81
82 /*%%%*/
83 /*
84  * search remote configuration.
85  * don't use port number to search if its value is either IPSEC_PORT_ANY.
86  * If matching anonymous entry, then new entry is copied from anonymous entry.
87  * If no anonymous entry found, then return NULL.
88  * OUT: NULL:   NG
89  *      Other:  remote configuration entry.
90  */
91 struct remoteconf *
92 getrmconf_strict(remote, allow_anon)
93         struct sockaddr *remote;
94         int allow_anon;
95 {
96         struct remoteconf *p;
97         struct remoteconf *anon = NULL;
98         int withport;
99         char buf[NI_MAXHOST + NI_MAXSERV + 10];
100         char addr[NI_MAXHOST], port[NI_MAXSERV];
101
102         withport = 0;
103
104         switch (remote->sa_family) {
105         case AF_INET:
106                 if (((struct sockaddr_in *)remote)->sin_port != IPSEC_PORT_ANY)
107                         withport = 1;
108                 break;
109 #ifdef INET6
110         case AF_INET6:
111                 if (((struct sockaddr_in6 *)remote)->sin6_port != IPSEC_PORT_ANY)
112                         withport = 1;
113                 break;
114 #endif
115         case AF_UNSPEC:
116                 break;
117
118         default:
119                 plog(LLV_ERROR, LOCATION, NULL,
120                         "invalid family: %d\n", remote->sa_family);
121                 exit(1);
122         }
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 *
162 getrmconf(remote)
163         struct sockaddr *remote;
164 {
165         return getrmconf_strict(remote, 1);
166 }
167
168 struct remoteconf *
169 newrmconf()
170 {
171         struct remoteconf *new;
172
173         new = racoon_calloc(1, sizeof(*new));
174         if (new == NULL)
175                 return NULL;
176
177         new->proposal = NULL;
178
179         /* set default */
180         new->doitype = IPSEC_DOI;
181         new->sittype = IPSECDOI_SIT_IDENTITY_ONLY;
182         new->idvtype = IDTYPE_UNDEFINED;
183         new->idvl_p = genlist_init();
184         new->nonce_size = DEFAULT_NONCE_SIZE;
185         new->passive = FALSE;
186         new->ike_frag = FALSE;
187         new->ini_contact = TRUE;
188         new->mode_cfg = FALSE;
189         new->pcheck_level = PROP_CHECK_STRICT;
190         new->verify_identifier = FALSE;
191         new->verify_cert = TRUE;
192         new->getcert_method = ISAKMP_GETCERT_PAYLOAD;
193         new->getcacert_method = ISAKMP_GETCERT_LOCALFILE;
194         new->cacerttype = ISAKMP_CERT_X509SIGN;
195         new->cacertfile = NULL;
196         new->send_cert = TRUE;
197         new->send_cr = TRUE;
198         new->support_proxy = FALSE;
199         bzero(&new->script[0], sizeof(char *) * (SCRIPT_MAX + 1));
200         new->gen_policy = FALSE;
201         new->retry_counter = lcconf->retry_counter;
202         new->retry_interval = lcconf->retry_interval;
203         new->nat_traversal = FALSE;
204         new->rsa_private = genlist_init();
205         new->rsa_public = genlist_init();
206         new->idv = NULL;
207         new->key = NULL;
208
209         new->dpd = TRUE; /* Enable DPD support by default */
210         new->dpd_interval = 0; /* Disable DPD checks by default */
211         new->dpd_retry = 5;
212         new->dpd_maxfails = 5;
213
214         return new;
215 }
216
217 struct remoteconf *
218 copyrmconf(remote)
219         struct sockaddr *remote;
220 {
221         struct remoteconf *new, *old;
222
223         old = getrmconf_strict (remote, 0);
224         if (old == NULL) {
225                 plog (LLV_ERROR, LOCATION, NULL,
226                       "Remote configuration for '%s' not found!\n",
227                       saddr2str (remote));
228                 return NULL;
229         }
230
231         new = duprmconf (old);
232
233         return new;
234 }
235
236 void *
237 dupidvl(entry, arg)
238         void *entry;
239         void *arg;
240 {
241         struct idspec *id;
242         struct idspec *old = (struct idspec *) entry;
243         id = newidspec();
244         if (!id) return (void *) -1;
245
246         if (set_identifier(&id->id, old->idtype, old->id) != 0) 
247                 return (void *) -1;
248
249         id->idtype = old->idtype;
250
251         genlist_append(arg, id);
252         return NULL;
253 }
254
255 struct remoteconf *
256 duprmconf (rmconf)
257         struct remoteconf *rmconf;
258 {
259         struct remoteconf *new;
260
261         new = racoon_calloc(1, sizeof(*new));
262         if (new == NULL)
263                 return NULL;
264         memcpy (new, rmconf, sizeof (*new));
265         // FIXME: We should duplicate the proposal as well.
266         // This is now handled in the cfparse.y
267         // new->proposal = ...;
268         
269         /* duplicate dynamic structures */
270         if (new->etypes)
271                 new->etypes=dupetypes(new->etypes);
272         new->idvl_p = genlist_init();
273         genlist_foreach(rmconf->idvl_p, dupidvl, new->idvl_p);
274
275         return new;
276 }
277
278 static void
279 idspec_free(void *data)
280 {
281         vfree (((struct idspec *)data)->id);
282         free (data);
283 }
284
285 void
286 delrmconf(rmconf)
287         struct remoteconf *rmconf;
288 {
289         if (rmconf->etypes)
290                 deletypes(rmconf->etypes);
291         if (rmconf->idvl_p)
292                 genlist_free(rmconf->idvl_p, idspec_free);
293         if (rmconf->dhgrp)
294                 oakley_dhgrp_free(rmconf->dhgrp);
295         if (rmconf->proposal)
296                 delisakmpsa(rmconf->proposal);
297         racoon_free(rmconf);
298 }
299
300 void
301 delisakmpsa(sa)
302         struct isakmpsa *sa;
303 {
304         if (sa->dhgrp)
305                 oakley_dhgrp_free(sa->dhgrp);
306         if (sa->next)
307                 delisakmpsa(sa->next);
308 #ifdef HAVE_GSSAPI
309         if (sa->gssid)
310                 vfree(sa->gssid);
311 #endif
312         racoon_free(sa);
313 }
314
315 struct etypes *
316 dupetypes(orig)
317         struct etypes *orig;
318 {
319         struct etypes *new;
320
321         if (!orig) 
322                 return NULL;
323
324         new = racoon_malloc(sizeof(struct etypes));
325         if (new == NULL) 
326                 return NULL;
327
328         new->type = orig->type;
329         new->next = NULL;
330
331         if (orig->next)
332                 new->next=dupetypes(orig->next);
333
334         return new;
335 }
336
337 void
338 deletypes(e)
339         struct etypes *e;
340 {
341         if (e->next)
342                 deletypes(e->next);
343         racoon_free(e);
344 }
345
346 /*
347  * insert into head of list.
348  */
349 void
350 insrmconf(new)
351         struct remoteconf *new;
352 {
353         TAILQ_INSERT_HEAD(&rmtree, new, chain);
354 }
355
356 void
357 remrmconf(rmconf)
358         struct remoteconf *rmconf;
359 {
360         TAILQ_REMOVE(&rmtree, rmconf, chain);
361 }
362
363 void
364 flushrmconf()
365 {
366         struct remoteconf *p, *next;
367
368         for (p = TAILQ_FIRST(&rmtree); p; p = next) {
369                 next = TAILQ_NEXT(p, chain);
370                 remrmconf(p);
371                 delrmconf(p);
372         }
373 }
374
375 void
376 initrmconf()
377 {
378         TAILQ_INIT(&rmtree);
379 }
380
381 /* check exchange type to be acceptable */
382 struct etypes *
383 check_etypeok(rmconf, etype)
384         struct remoteconf *rmconf;
385         u_int8_t etype;
386 {
387         struct etypes *e;
388
389         for (e = rmconf->etypes; e != NULL; e = e->next) {
390                 if (e->type == etype)
391                         break;
392         }
393
394         return e;
395 }
396
397 /*%%%*/
398 struct isakmpsa *
399 newisakmpsa()
400 {
401         struct isakmpsa *new;
402
403         new = racoon_calloc(1, sizeof(*new));
404         if (new == NULL)
405                 return NULL;
406
407         /*
408          * Just for sanity, make sure this is initialized.  This is
409          * filled in for real when the ISAKMP proposal is configured.
410          */
411         new->vendorid = VENDORID_UNKNOWN;
412
413         new->next = NULL;
414         new->rmconf = NULL;
415 #ifdef HAVE_GSSAPI
416         new->gssid = NULL;
417 #endif
418
419         return new;
420 }
421
422 /*
423  * insert into tail of list.
424  */
425 void
426 insisakmpsa(new, rmconf)
427         struct isakmpsa *new;
428         struct remoteconf *rmconf;
429 {
430         struct isakmpsa *p;
431
432         new->rmconf = rmconf;
433
434         if (rmconf->proposal == NULL) {
435                 rmconf->proposal = new;
436                 return;
437         }
438
439         for (p = rmconf->proposal; p->next != NULL; p = p->next)
440                 ;
441         p->next = new;
442
443         return;
444 }
445
446 struct remoteconf *
447 foreachrmconf(rmconf_func_t rmconf_func, void *data)
448 {
449         struct remoteconf *p, *ret = NULL;
450         
451         TAILQ_FOREACH_REVERSE(p, &rmtree, _rmtree, chain) {
452                 ret = (*rmconf_func)(p, data);
453                 if (ret)
454                         break;
455         }
456
457         return ret;
458 }
459
460 static void *
461 dump_peers_identifiers (void *entry, void *arg)
462 {
463         struct idspec *id = (struct idspec*) entry;
464         char buf[1024], *pbuf;
465         pbuf = buf;
466         pbuf += sprintf (pbuf, "\tpeers_identifier %s",
467                          s_idtype (id->idtype));
468         if (id->id)
469                 pbuf += sprintf (pbuf, " \"%s\"", id->id->v);
470         plog(LLV_INFO, LOCATION, NULL, "%s;\n", buf);
471         return NULL;
472 }
473
474 static struct remoteconf *
475 dump_rmconf_single (struct remoteconf *p, void *data)
476 {
477         struct etypes *etype = p->etypes;
478         struct isakmpsa *prop = p->proposal;
479         char buf[1024], *pbuf;
480
481         pbuf = buf;
482         pbuf += sprintf(pbuf, "remote %s", saddr2str(p->remote));
483         if (p->inherited_from)
484                 pbuf += sprintf(pbuf, " inherit %s",
485                                 saddr2str(p->inherited_from->remote));
486         plog(LLV_INFO, LOCATION, NULL, "%s {\n", buf);
487         pbuf = buf;
488         pbuf += sprintf(pbuf, "\texchange_type ");
489         while (etype) {
490                 pbuf += sprintf (pbuf, "%s%s", s_etype(etype->type),
491                                  etype->next != NULL ? ", " : ";\n");
492                 etype = etype->next;
493         }
494         plog(LLV_INFO, LOCATION, NULL, "%s", buf);
495         plog(LLV_INFO, LOCATION, NULL, "\tdoi %s;\n", s_doi(p->doitype));
496         pbuf = buf;
497         pbuf += sprintf(pbuf, "\tmy_identifier %s", s_idtype (p->idvtype));
498         if (p->idvtype == IDTYPE_ASN1DN) {
499                 plog(LLV_INFO, LOCATION, NULL, "%s;\n", buf);
500                 plog(LLV_INFO, LOCATION, NULL, "\tcertificate_type %s \"%s\" \"%s\";\n",
501                         p->certtype == ISAKMP_CERT_X509SIGN ? "x509" : "*UNKNOWN*",
502                         p->mycertfile, p->myprivfile);
503                 switch (p->getcert_method) {
504                   case 0:
505                         break;
506                   case ISAKMP_GETCERT_PAYLOAD:
507                         plog(LLV_INFO, LOCATION, NULL, "\t/* peers certificate from payload */\n");
508                         break;
509                   case ISAKMP_GETCERT_LOCALFILE:
510                         plog(LLV_INFO, LOCATION, NULL, "\tpeers_certfile \"%s\";\n", p->peerscertfile);
511                         break;
512                   case ISAKMP_GETCERT_DNS:
513                         plog(LLV_INFO, LOCATION, NULL, "\tpeer_certfile dnssec;\n");
514                         break;
515                   default:
516                         plog(LLV_INFO, LOCATION, NULL, "\tpeers_certfile *UNKNOWN* (%d)\n", p->getcert_method);
517                 }
518         }
519         else {
520                 if (p->idv)
521                         pbuf += sprintf (pbuf, " \"%s\"", p->idv->v);
522                 plog(LLV_INFO, LOCATION, NULL, "%s;\n", buf);
523                 genlist_foreach(p->idvl_p, &dump_peers_identifiers, NULL);
524         }
525
526         plog(LLV_INFO, LOCATION, NULL, "\tsend_cert %s;\n",
527                 s_switch (p->send_cert));
528         plog(LLV_INFO, LOCATION, NULL, "\tsend_cr %s;\n",
529                 s_switch (p->send_cr));
530         plog(LLV_INFO, LOCATION, NULL, "\tverify_cert %s;\n",
531                 s_switch (p->verify_cert));
532         plog(LLV_INFO, LOCATION, NULL, "\tverify_identifier %s;\n",
533                 s_switch (p->verify_identifier));
534         plog(LLV_INFO, LOCATION, NULL, "\tnat_traversal %s;\n",
535                 p->nat_traversal == NATT_FORCE ?
536                         "force" : s_switch (p->nat_traversal));
537         plog(LLV_INFO, LOCATION, NULL, "\tnonce_size %d;\n",
538                 p->nonce_size);
539         plog(LLV_INFO, LOCATION, NULL, "\tpassive %s;\n",
540                 s_switch (p->passive));
541         plog(LLV_INFO, LOCATION, NULL, "\tike_frag %s;\n",
542                 s_switch (p->ike_frag));
543         plog(LLV_INFO, LOCATION, NULL, "\tinitial_contact %s;\n",
544                 s_switch (p->ini_contact));
545         plog(LLV_INFO, LOCATION, NULL, "\tgenerate_policy %s;\n",
546                 s_switch (p->gen_policy));
547         plog(LLV_INFO, LOCATION, NULL, "\tsupport_proxy %s;\n",
548                 s_switch (p->support_proxy));
549
550         while (prop) {
551                 plog(LLV_INFO, LOCATION, NULL, "\n");
552                 plog(LLV_INFO, LOCATION, NULL,
553                         "\t/* prop_no=%d, trns_no=%d, rmconf=%s */\n",
554                         prop->prop_no, prop->trns_no,
555                         saddr2str(prop->rmconf->remote));
556                 plog(LLV_INFO, LOCATION, NULL, "\tproposal {\n");
557                 plog(LLV_INFO, LOCATION, NULL, "\t\tlifetime time %lu sec;\n",
558                         (long)prop->lifetime);
559                 plog(LLV_INFO, LOCATION, NULL, "\t\tlifetime bytes %zd;\n",
560                         prop->lifebyte);
561                 plog(LLV_INFO, LOCATION, NULL, "\t\tdh_group %s;\n",
562                         alg_oakley_dhdef_name(prop->dh_group));
563                 plog(LLV_INFO, LOCATION, NULL, "\t\tencryption_algorithm %s;\n", 
564                         alg_oakley_encdef_name(prop->enctype));
565                 plog(LLV_INFO, LOCATION, NULL, "\t\thash_algorithm %s;\n", 
566                         alg_oakley_hashdef_name(prop->hashtype));
567                 plog(LLV_INFO, LOCATION, NULL, "\t\tauthentication_method %s;\n", 
568                         alg_oakley_authdef_name(prop->authmethod));
569                 plog(LLV_INFO, LOCATION, NULL, "\t}\n");
570                 prop = prop->next;
571         }
572         plog(LLV_INFO, LOCATION, NULL, "}\n");
573         plog(LLV_INFO, LOCATION, NULL, "\n");
574
575         return NULL;
576 }
577
578 void
579 dumprmconf()
580 {
581         foreachrmconf (dump_rmconf_single, NULL);
582 }
583
584 struct idspec *
585 newidspec()
586 {
587         struct idspec *new;
588
589         new = racoon_calloc(1, sizeof(*new));
590         if (new == NULL)
591                 return NULL;
592         new->idtype = IDTYPE_ADDRESS;
593
594         return new;
595 }
596