1/*	$KAME: cfparse.y,v 1.112 2002/02/21 14:47:38 sakane Exp $	*/
2
3%{
4#include <sys/types.h>
5#include <sys/param.h>
6#include <sys/queue.h>
7#include <sys/socket.h>
8
9#include <netinet/in.h>
10#include <netinet/ipsec.h>
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <string.h>
15#include <errno.h>
16#include <netdb.h>
17#if !defined(HAVE_GETADDRINFO) || !defined(HAVE_GETNAMEINFO)
18#include "addrinfo.h"
19#endif
20
21#include "var.h"
22#include "misc.h"
23#include "vmbuf.h"
24#include "plog.h"
25#include "sockmisc.h"
26#include "str2val.h"
27#include "debug.h"
28
29#include "cfparse.h"
30#include "cftoken.h"
31#include "algorithm.h"
32#include "localconf.h"
33#include "policy.h"
34#include "sainfo.h"
35#include "oakley.h"
36#include "pfkey.h"
37#include "remoteconf.h"
38#include "grabmyaddr.h"
39#include "isakmp_var.h"
40#include "handler.h"
41#include "isakmp.h"
42#include "ipsec_doi.h"
43#include "strnames.h"
44#include "gcmalloc.h"
45#ifdef HAVE_GSSAPI
46#include "gssapi.h"
47#endif
48#include "vendorid.h"
49
50struct proposalspec {
51	time_t lifetime;		/* for isakmp/ipsec */
52	int lifebyte;			/* for isakmp/ipsec */
53	struct secprotospec *spspec;	/* the head is always current spec. */
54	struct proposalspec *next;	/* the tail is the most prefered. */
55	struct proposalspec *prev;
56};
57
58struct secprotospec {
59	int prop_no;
60	int trns_no;
61	int strength;		/* for isakmp/ipsec */
62	int encklen;		/* for isakmp/ipsec */
63	time_t lifetime;	/* for isakmp */
64	int lifebyte;		/* for isakmp */
65	int proto_id;		/* for ipsec (isakmp?) */
66	int ipsec_level;	/* for ipsec */
67	int encmode;		/* for ipsec */
68	int vendorid;		/* for isakmp */
69	char *gssid;
70	struct sockaddr *remote;
71	int algclass[MAXALGCLASS];
72
73	struct secprotospec *next;	/* the tail is the most prefiered. */
74	struct secprotospec *prev;
75	struct proposalspec *back;
76};
77
78static int num2dhgroup[] = {
79	0,
80	OAKLEY_ATTR_GRP_DESC_MODP768,
81	OAKLEY_ATTR_GRP_DESC_MODP1024,
82	OAKLEY_ATTR_GRP_DESC_EC2N155,
83	OAKLEY_ATTR_GRP_DESC_EC2N185,
84	OAKLEY_ATTR_GRP_DESC_MODP1536,
85};
86
87static struct remoteconf *cur_rmconf;
88static int tmpalgtype[MAXALGCLASS];
89static struct sainfo *cur_sainfo;
90static int cur_algclass;
91
92static struct proposalspec *prhead;	/* the head is always current. */
93
94static struct proposalspec *newprspec __P((void));
95static void cleanprhead __P((void));
96static void insprspec __P((struct proposalspec *, struct proposalspec **));
97static struct secprotospec *newspspec __P((void));
98static void insspspec __P((struct secprotospec *, struct proposalspec **));
99
100static int set_isakmp_proposal
101	__P((struct remoteconf *, struct proposalspec *));
102static void clean_tmpalgtype __P((void));
103static int expand_isakmpspec __P((int, int, int *,
104	int, int, time_t, int, int, int, char *, struct remoteconf *));
105
106#if 0
107static int fix_lifebyte __P((u_long));
108#endif
109%}
110
111%union {
112	unsigned long num;
113	vchar_t *val;
114	struct remoteconf *rmconf;
115	struct sockaddr *saddr;
116	struct sainfoalg *alg;
117}
118
119	/* path */
120%token PATH PATHTYPE
121	/* include */
122%token INCLUDE
123	/* self information */
124%token IDENTIFIER VENDORID
125	/* logging */
126%token LOGGING LOGLEV
127	/* padding */
128%token PADDING PAD_RANDOMIZE PAD_RANDOMIZELEN PAD_MAXLEN PAD_STRICT PAD_EXCLTAIL
129	/* listen */
130%token LISTEN X_ISAKMP X_ADMIN STRICT_ADDRESS
131	/* timer */
132%token RETRY RETRY_COUNTER RETRY_INTERVAL RETRY_PERSEND
133%token RETRY_PHASE1 RETRY_PHASE2
134	/* algorithm */
135%token ALGORITHM_CLASS ALGORITHMTYPE STRENGTHTYPE
136	/* sainfo */
137%token SAINFO
138	/* remote */
139%token REMOTE ANONYMOUS
140%token EXCHANGE_MODE EXCHANGETYPE DOI DOITYPE SITUATION SITUATIONTYPE
141%token CERTIFICATE_TYPE CERTTYPE PEERS_CERTFILE VERIFY_CERT SEND_CERT SEND_CR
142%token IDENTIFIERTYPE MY_IDENTIFIER PEERS_IDENTIFIER VERIFY_IDENTIFIER
143%token DNSSEC CERT_X509
144%token NONCE_SIZE DH_GROUP KEEPALIVE PASSIVE INITIAL_CONTACT
145%token PROPOSAL_CHECK PROPOSAL_CHECK_LEVEL
146%token GENERATE_POLICY SUPPORT_MIP6
147%token PROPOSAL
148%token EXEC_PATH EXEC_COMMAND EXEC_SUCCESS EXEC_FAILURE
149%token GSSAPI_ID
150%token COMPLEX_BUNDLE
151
152%token PREFIX PORT PORTANY UL_PROTO ANY
153%token PFS_GROUP LIFETIME LIFETYPE_TIME LIFETYPE_BYTE STRENGTH
154
155%token NUMBER SWITCH BOOLEAN
156%token HEXSTRING QUOTEDSTRING ADDRSTRING
157%token UNITTYPE_BYTE UNITTYPE_KBYTES UNITTYPE_MBYTES UNITTYPE_TBYTES
158%token UNITTYPE_SEC UNITTYPE_MIN UNITTYPE_HOUR
159%token EOS BOC EOC COMMA
160
161%type <num> NUMBER BOOLEAN SWITCH keylength
162%type <num> PATHTYPE IDENTIFIERTYPE LOGLEV
163%type <num> ALGORITHM_CLASS dh_group_num
164%type <num> ALGORITHMTYPE STRENGTHTYPE
165%type <num> PREFIX prefix PORT port ike_port
166%type <num> ul_proto UL_PROTO
167%type <num> EXCHANGETYPE DOITYPE SITUATIONTYPE
168%type <num> CERTTYPE CERT_X509 PROPOSAL_CHECK_LEVEL
169%type <num> unittype_time unittype_byte
170%type <val> QUOTEDSTRING HEXSTRING ADDRSTRING sainfo_id
171%type <val> identifierstring
172%type <saddr> remote_index ike_addrinfo_port
173%type <alg> algorithm
174
175%%
176
177statements
178	:	/* nothing */
179	|	statements statement
180	;
181statement
182	:	path_statement
183	|	include_statement
184	|	identifier_statement
185	|	logging_statement
186	|	padding_statement
187	|	listen_statement
188	|	timer_statement
189	|	sainfo_statement
190	|	remote_statement
191	|	special_statement
192	;
193
194	/* path */
195path_statement
196	:	PATH PATHTYPE QUOTEDSTRING
197		{
198			if ($2 > LC_PATHTYPE_MAX) {
199				yyerror("invalid path type %d", $2);
200				return -1;
201			}
202
203			/* free old pathinfo */
204			if (lcconf->pathinfo[$2])
205				racoon_free(lcconf->pathinfo[$2]);
206
207			/* set new pathinfo */
208			lcconf->pathinfo[$2] = strdup($3->v);
209			vfree($3);
210		}
211		EOS
212	;
213
214	/* special */
215special_statement
216	:	COMPLEX_BUNDLE SWITCH { lcconf->complex_bundle = $2; } EOS
217	;
218
219	/* include */
220include_statement
221	:	INCLUDE QUOTEDSTRING
222		{
223			char path[MAXPATHLEN];
224
225			getpathname(path, sizeof(path),
226				LC_PATHTYPE_INCLUDE, $2->v);
227			vfree($2);
228			if (yycf_switch_buffer(path) != 0)
229				return -1;
230		}
231		EOS
232	;
233
234	/* self infomation */
235identifier_statement
236	:	IDENTIFIER identifier_stmt
237	;
238identifier_stmt
239	:	VENDORID
240		{
241			/*XXX to be deleted */
242		}
243		QUOTEDSTRING EOS
244	|	IDENTIFIERTYPE QUOTEDSTRING
245		{
246			/*XXX to be deleted */
247			$2->l--;	/* nuke '\0' */
248			lcconf->ident[$1] = $2;
249			if (lcconf->ident[$1] == NULL) {
250				yyerror("failed to set my ident: %s",
251					strerror(errno));
252				return -1;
253			}
254		}
255		EOS
256	;
257
258	/* logging */
259logging_statement
260	:	LOGGING log_level EOS
261	;
262log_level
263	:	HEXSTRING
264		{
265			/*
266			 * XXX ignore it because this specification
267			 * will be obsoleted.
268			 */
269			yywarn("see racoon.conf(5), such a log specification will be obsoleted.");
270			vfree($1);
271		}
272	|	LOGLEV
273		{
274			/*
275			 * set the loglevel by configuration file only when
276			 * the command line did not specify any loglevel.
277			 */
278			if (loglevel <= LLV_BASE)
279				loglevel += $1;
280		}
281	;
282
283	/* padding */
284padding_statement
285	:	PADDING BOC padding_stmts EOC
286	;
287padding_stmts
288	:	/* nothing */
289	|	padding_stmts padding_stmt
290	;
291padding_stmt
292	:	PAD_RANDOMIZE SWITCH { lcconf->pad_random = $2; } EOS
293	|	PAD_RANDOMIZELEN SWITCH { lcconf->pad_randomlen = $2; } EOS
294	|	PAD_MAXLEN NUMBER { lcconf->pad_maxsize = $2; } EOS
295	|	PAD_STRICT SWITCH { lcconf->pad_strict = $2; } EOS
296	|	PAD_EXCLTAIL SWITCH { lcconf->pad_excltail = $2; } EOS
297	;
298
299	/* listen */
300listen_statement
301	:	LISTEN BOC listen_stmts EOC
302	;
303listen_stmts
304	:	/* nothing */
305	|	listen_stmts listen_stmt
306	;
307listen_stmt
308	:	X_ISAKMP ike_addrinfo_port
309		{
310			struct myaddrs *p;
311
312			p = newmyaddr();
313			if (p == NULL) {
314				yyerror("failed to allocate myaddrs");
315				return -1;
316			}
317			p->addr = $2;
318			if (p->addr == NULL) {
319				yyerror("failed to copy sockaddr ");
320				delmyaddr(p);
321				return -1;
322			}
323
324			insmyaddr(p, &lcconf->myaddrs);
325
326			lcconf->autograbaddr = 0;
327		}
328		EOS
329	|	X_ADMIN
330		{
331			yyerror("admin directive is obsoleted.");
332		}
333		PORT EOS
334	|	STRICT_ADDRESS { lcconf->strict_address = TRUE; } EOS
335	;
336ike_addrinfo_port
337	:	ADDRSTRING ike_port
338		{
339			char portbuf[10];
340
341			snprintf(portbuf, sizeof(portbuf), "%ld", $2);
342			$$ = str2saddr($1->v, portbuf);
343			vfree($1);
344			if (!$$)
345				return -1;
346		}
347	;
348ike_port
349	:	/* nothing */	{ $$ = PORT_ISAKMP; }
350	|	PORT		{ $$ = $1; }
351	;
352
353	/* timer */
354timer_statement
355	:	RETRY BOC timer_stmts EOC
356	;
357timer_stmts
358	:	/* nothing */
359	|	timer_stmts timer_stmt
360	;
361timer_stmt
362	:	RETRY_COUNTER NUMBER
363		{
364			lcconf->retry_counter = $2;
365		}
366		EOS
367	|	RETRY_INTERVAL NUMBER unittype_time
368		{
369			lcconf->retry_interval = $2 * $3;
370		}
371		EOS
372	|	RETRY_PERSEND NUMBER
373		{
374			lcconf->count_persend = $2;
375		}
376		EOS
377	|	RETRY_PHASE1 NUMBER unittype_time
378		{
379			lcconf->retry_checkph1 = $2 * $3;
380		}
381		EOS
382	|	RETRY_PHASE2 NUMBER unittype_time
383		{
384			lcconf->wait_ph2complete = $2 * $3;
385		}
386		EOS
387	;
388
389	/* sainfo */
390sainfo_statement
391	:	SAINFO
392		{
393			cur_sainfo = newsainfo();
394			if (cur_sainfo == NULL) {
395				yyerror("failed to allocate sainfo");
396				return -1;
397			}
398		}
399		sainfo_name BOC sainfo_specs
400		{
401			struct sainfo *check;
402
403			/* default */
404			if (cur_sainfo->algs[algclass_ipsec_enc] == 0) {
405				yyerror("no encryption algorithm at %s",
406					sainfo2str(cur_sainfo));
407				return -1;
408			}
409			if (cur_sainfo->algs[algclass_ipsec_auth] == 0) {
410				yyerror("no authentication algorithm at %s",
411					sainfo2str(cur_sainfo));
412				return -1;
413			}
414			if (cur_sainfo->algs[algclass_ipsec_comp] == 0) {
415				yyerror("no compression algorithm at %s",
416					sainfo2str(cur_sainfo));
417				return -1;
418			}
419
420			/* duplicate check */
421			check = getsainfo(cur_sainfo->idsrc, cur_sainfo->iddst);
422			if (check && (!check->idsrc && !cur_sainfo->idsrc)) {
423				yyerror("duplicated sainfo: %s",
424					sainfo2str(cur_sainfo));
425				return -1;
426			}
427			inssainfo(cur_sainfo);
428		}
429		EOC
430	;
431sainfo_name
432	:	ANONYMOUS
433		{
434			cur_sainfo->idsrc = NULL;
435			cur_sainfo->iddst = NULL;
436		}
437	|	sainfo_id sainfo_id
438		{
439			cur_sainfo->idsrc = $1;
440			cur_sainfo->iddst = $2;
441		}
442	;
443sainfo_id
444	:	IDENTIFIERTYPE ADDRSTRING prefix port ul_proto
445		{
446			char portbuf[10];
447			struct sockaddr *saddr;
448
449			if (($5 == IPPROTO_ICMP || $5 == IPPROTO_ICMPV6)
450			 && ($4 != IPSEC_PORT_ANY || $4 != IPSEC_PORT_ANY)) {
451				yyerror("port number must be \"any\".");
452				return -1;
453			}
454
455			snprintf(portbuf, sizeof(portbuf), "%lu", $4);
456			saddr = str2saddr($2->v, portbuf);
457			vfree($2);
458			if (saddr == NULL)
459				return -1;
460
461			switch (saddr->sa_family) {
462			case AF_INET:
463				if ($5 == IPPROTO_ICMPV6) {
464					yyerror("upper layer protocol mismatched.\n");
465					racoon_free(saddr);
466					return -1;
467				}
468				$$ = ipsecdoi_sockaddr2id(saddr,
469					$3 == ~0 ? (sizeof(struct in_addr) << 3): $3,
470					$5);
471				break;
472#ifdef INET6
473			case AF_INET6:
474				if ($5 == IPPROTO_ICMP) {
475					yyerror("upper layer protocol mismatched.\n");
476					racoon_free(saddr);
477					return -1;
478				}
479				$$ = ipsecdoi_sockaddr2id(saddr,
480					$3 == ~0 ? (sizeof(struct in6_addr) << 3) : $3,
481					$5);
482				break;
483#endif
484			default:
485				yyerror("invalid family: %d", saddr->sa_family);
486				break;
487			}
488			racoon_free(saddr);
489			if ($$ == NULL)
490				return -1;
491		}
492	|	IDENTIFIERTYPE QUOTEDSTRING
493		{
494			struct ipsecdoi_id_b *id_b;
495
496			if ($1 == IDTYPE_ASN1DN) {
497				yyerror("id type forbidden: %d", $1);
498				return -1;
499			}
500
501			$2->l--;
502
503			$$ = vmalloc(sizeof(*id_b) + $2->l);
504			if ($$ == NULL) {
505				yyerror("failed to allocate identifier");
506				return -1;
507			}
508
509			id_b = (struct ipsecdoi_id_b *)$$->v;
510			id_b->type = idtype2doi($1);
511
512			id_b->proto_id = 0;
513			id_b->port = 0;
514
515			memcpy($$->v + sizeof(*id_b), $2->v, $2->l);
516		}
517	;
518sainfo_specs
519	:	/* nothing */
520	|	sainfo_specs sainfo_spec
521	;
522sainfo_spec
523	:	PFS_GROUP dh_group_num
524		{
525			cur_sainfo->pfs_group = $2;
526		}
527		EOS
528	|	LIFETIME LIFETYPE_TIME NUMBER unittype_time
529		{
530			cur_sainfo->lifetime = $3 * $4;
531		}
532		EOS
533	|	LIFETIME LIFETYPE_BYTE NUMBER unittype_byte
534		{
535#if 1
536			yyerror("byte lifetime support is deprecated");
537			return -1;
538#else
539			cur_sainfo->lifebyte = fix_lifebyte($3 * $4);
540			if (cur_sainfo->lifebyte == 0)
541				return -1;
542#endif
543		}
544		EOS
545	|	ALGORITHM_CLASS {
546			cur_algclass = $1;
547		}
548		algorithms EOS
549	|	IDENTIFIER IDENTIFIERTYPE
550		{
551			yyerror("it's deprecated to specify a identifier in phase 2");
552		}
553		EOS
554	|	MY_IDENTIFIER IDENTIFIERTYPE QUOTEDSTRING
555		{
556			yyerror("it's deprecated to specify a identifier in phase 2");
557		}
558		EOS
559	;
560
561algorithms
562	:	algorithm
563		{
564			inssainfoalg(&cur_sainfo->algs[cur_algclass], $1);
565		}
566	|	algorithm
567		{
568			inssainfoalg(&cur_sainfo->algs[cur_algclass], $1);
569		}
570		COMMA algorithms
571	;
572algorithm
573	:	ALGORITHMTYPE keylength
574		{
575			int defklen;
576
577			$$ = newsainfoalg();
578			if ($$ == NULL) {
579				yyerror("failed to get algorithm alocation");
580				return -1;
581			}
582
583			$$->alg = algtype2doi(cur_algclass, $1);
584			if ($$->alg == -1) {
585				yyerror("algorithm mismatched");
586				racoon_free($$);
587				return -1;
588			}
589
590			defklen = default_keylen(cur_algclass, $1);
591			if (defklen == 0) {
592				if ($2) {
593					yyerror("keylen not allowed");
594					racoon_free($$);
595					return -1;
596				}
597			} else {
598				if ($2 && check_keylen(cur_algclass, $1, $2) < 0) {
599					yyerror("invalid keylen %d", $2);
600					racoon_free($$);
601					return -1;
602				}
603			}
604
605			if ($2)
606				$$->encklen = $2;
607			else
608				$$->encklen = defklen;
609
610			/* check if it's supported algorithm by kernel */
611			if (!(cur_algclass == algclass_ipsec_auth && $1 == algtype_non_auth)
612			 && pk_checkalg(cur_algclass, $1, $$->encklen)) {
613				int a = algclass2doi(cur_algclass);
614				int b = algtype2doi(cur_algclass, $1);
615				if (a == IPSECDOI_ATTR_AUTH)
616					a = IPSECDOI_PROTO_IPSEC_AH;
617				yyerror("algorithm %s not supported",
618					s_ipsecdoi_trns(a, b));
619				racoon_free($$);
620				return -1;
621			}
622		}
623	;
624prefix
625	:	/* nothing */ { $$ = ~0; }
626	|	PREFIX { $$ = $1; }
627	;
628port
629	:	/* nothing */ { $$ = IPSEC_PORT_ANY; }
630	|	PORT { $$ = $1; }
631	|	PORTANY { $$ = IPSEC_PORT_ANY; }
632	;
633ul_proto
634	:	NUMBER { $$ = $1; }
635	|	UL_PROTO { $$ = $1; }
636	|	ANY { $$ = IPSEC_ULPROTO_ANY; }
637	;
638keylength
639	:	/* nothing */ { $$ = 0; }
640	|	NUMBER { $$ = $1; }
641	;
642
643	/* remote */
644remote_statement
645	:	REMOTE remote_index
646		{
647			struct remoteconf *new;
648			struct proposalspec *prspec;
649
650			new = newrmconf();
651			if (new == NULL) {
652				yyerror("failed to get new remoteconf.");
653				return -1;
654			}
655
656			new->remote = $2;
657			cur_rmconf = new;
658
659			prspec = newprspec();
660			if (prspec == NULL)
661				return -1;
662			prspec->lifetime = oakley_get_defaultlifetime();
663			insprspec(prspec, &prhead);
664		}
665		BOC remote_specs
666		{
667			/* check a exchange mode */
668			if (cur_rmconf->etypes == NULL) {
669				yyerror("no exchange mode specified.\n");
670				return -1;
671			}
672
673			if (cur_rmconf->idvtype == IDTYPE_ASN1DN
674			 && cur_rmconf->mycertfile == NULL) {
675				yyerror("id type mismatched due to "
676					"no CERT defined.\n");
677				return -1;
678			}
679
680			if (set_isakmp_proposal(cur_rmconf, prhead) != 0)
681				return -1;
682
683			/* DH group settting if aggressive mode is there. */
684			if (check_etypeok(cur_rmconf, ISAKMP_ETYPE_AGG) != NULL) {
685				struct isakmpsa *p;
686				int b = 0;
687
688				/* DH group */
689				for (p = cur_rmconf->proposal; p; p = p->next) {
690					if (b == 0 || (b && b == p->dh_group)) {
691						b = p->dh_group;
692						continue;
693					}
694					yyerror("DH group must be equal "
695						"to each proposals's "
696						"when aggressive mode is "
697						"used.\n");
698					return -1;
699				}
700				cur_rmconf->dh_group = b;
701
702				if (cur_rmconf->dh_group == 0) {
703					yyerror("DH group must be required.\n");
704					return -1;
705				}
706
707				/* DH group settting if PFS is required. */
708				if (oakley_setdhgroup(cur_rmconf->dh_group,
709						&cur_rmconf->dhgrp) < 0) {
710					yyerror("failed to set DH value.\n");
711					return -1;
712				}
713			}
714
715			insrmconf(cur_rmconf);
716
717			cleanprhead();
718		}
719		EOC
720	;
721remote_index
722	:	ANONYMOUS ike_port
723		{
724			$$ = newsaddr(sizeof(struct sockaddr *));
725			$$->sa_family = AF_UNSPEC;
726			((struct sockaddr_in *)$$)->sin_port = htons($2);
727		}
728	|	ike_addrinfo_port
729		{
730			$$ = $1;
731			if ($$ == NULL) {
732				yyerror("failed to allocate sockaddr");
733				return -1;
734			}
735		}
736	;
737remote_specs
738	:	/* nothing */
739	|	remote_specs remote_spec
740	;
741remote_spec
742	:	EXCHANGE_MODE exchange_types EOS
743	|	DOI DOITYPE { cur_rmconf->doitype = $2; } EOS
744	|	SITUATION SITUATIONTYPE { cur_rmconf->sittype = $2; } EOS
745	|	CERTIFICATE_TYPE cert_spec
746	|	PEERS_CERTFILE QUOTEDSTRING
747		{
748#ifdef HAVE_SIGNING_C
749			cur_rmconf->getcert_method = ISAKMP_GETCERT_LOCALFILE;
750			cur_rmconf->peerscertfile = strdup($2->v);
751			vfree($2);
752#else
753			yyerror("directive not supported");
754			return -1;
755#endif
756		}
757		EOS
758	|	PEERS_CERTFILE DNSSEC
759		{
760#ifdef HAVE_SIGNING_C
761			cur_rmconf->getcert_method = ISAKMP_GETCERT_DNS;
762			cur_rmconf->peerscertfile = NULL;
763#else
764			yyerror("directive not supported");
765			return -1;
766#endif
767		}
768		EOS
769	|	VERIFY_CERT SWITCH { cur_rmconf->verify_cert = $2; } EOS
770	|	SEND_CERT SWITCH { cur_rmconf->send_cert = $2; } EOS
771	|	SEND_CR SWITCH { cur_rmconf->send_cr = $2; } EOS
772	|	IDENTIFIER IDENTIFIERTYPE
773		{
774			/*XXX to be deleted */
775			cur_rmconf->idvtype = $2;
776		}
777		EOS
778	|	MY_IDENTIFIER IDENTIFIERTYPE identifierstring
779		{
780			if (set_identifier(&cur_rmconf->idv, $2, $3) != 0) {
781				yyerror("failed to set identifer.\n");
782				return -1;
783			}
784			cur_rmconf->idvtype = $2;
785		}
786		EOS
787	|	PEERS_IDENTIFIER IDENTIFIERTYPE identifierstring
788		{
789			if (set_identifier(&cur_rmconf->idv_p, $2, $3) != 0) {
790				yyerror("failed to set identifer.\n");
791				return -1;
792			}
793			cur_rmconf->idvtype_p = $2;
794		}
795		EOS
796	|	VERIFY_IDENTIFIER SWITCH { cur_rmconf->verify_identifier = $2; } EOS
797	|	NONCE_SIZE NUMBER { cur_rmconf->nonce_size = $2; } EOS
798	|	DH_GROUP
799		{
800			yyerror("dh_group cannot be defined here.");
801			return -1;
802		}
803		dh_group_num EOS
804	|	KEEPALIVE { cur_rmconf->keepalive = TRUE; } EOS
805	|	PASSIVE SWITCH { cur_rmconf->passive = $2; } EOS
806	|	GENERATE_POLICY SWITCH { cur_rmconf->gen_policy = $2; } EOS
807	|	SUPPORT_MIP6 SWITCH { cur_rmconf->support_mip6 = $2; } EOS
808	|	INITIAL_CONTACT SWITCH { cur_rmconf->ini_contact = $2; } EOS
809	|	PROPOSAL_CHECK PROPOSAL_CHECK_LEVEL { cur_rmconf->pcheck_level = $2; } EOS
810	|	LIFETIME LIFETYPE_TIME NUMBER unittype_time
811		{
812			prhead->lifetime = $3 * $4;
813		}
814		EOS
815	|	LIFETIME LIFETYPE_BYTE NUMBER unittype_byte
816		{
817#if 1
818			yyerror("byte lifetime support is deprecated");
819			return -1;
820#else
821			yywarn("the lifetime of bytes in phase 1 "
822				"will be ignored at the moment.");
823			prhead->lifebyte = fix_lifebyte($3 * $4);
824			if (prhead->lifebyte == 0)
825				return -1;
826#endif
827		}
828		EOS
829	|	PROPOSAL
830		{
831			struct secprotospec *spspec;
832
833			spspec = newspspec();
834			if (spspec == NULL)
835				return -1;
836			insspspec(spspec, &prhead);
837		}
838		BOC isakmpproposal_specs EOC
839	;
840exchange_types
841	:	/* nothing */
842	|	exchange_types EXCHANGETYPE
843		{
844			struct etypes *new;
845			new = racoon_malloc(sizeof(struct etypes));
846			if (new == NULL) {
847				yyerror("filed to allocate etypes");
848				return -1;
849			}
850			new->type = $2;
851			new->next = NULL;
852			if (cur_rmconf->etypes == NULL)
853				cur_rmconf->etypes = new;
854			else {
855				struct etypes *p;
856				for (p = cur_rmconf->etypes;
857				     p->next != NULL;
858				     p = p->next)
859					;
860				p->next = new;
861			}
862		}
863	;
864cert_spec
865	:	CERT_X509 QUOTEDSTRING QUOTEDSTRING
866		{
867#ifdef HAVE_SIGNING_C
868			cur_rmconf->certtype = $1;
869			cur_rmconf->mycertfile = strdup($2->v);
870			vfree($2);
871			cur_rmconf->myprivfile = strdup($3->v);
872			vfree($3);
873#else
874			yyerror("directive not supported");
875			return -1;
876#endif
877		}
878		EOS
879	;
880dh_group_num
881	:	ALGORITHMTYPE
882		{
883			$$ = algtype2doi(algclass_isakmp_dh, $1);
884			if ($$ == -1) {
885				yyerror("must be DH group");
886				return -1;
887			}
888		}
889	|	NUMBER
890		{
891			if (ARRAYLEN(num2dhgroup) > $1 && num2dhgroup[$1] != 0) {
892				$$ = num2dhgroup[$1];
893			} else {
894				yyerror("must be DH group");
895				return -1;
896			}
897		}
898	;
899identifierstring
900	:	/* nothing */ { $$ = NULL; }
901	|	ADDRSTRING { $$ = $1; }
902	|	QUOTEDSTRING { $$ = $1; }
903	;
904isakmpproposal_specs
905	:	/* nothing */
906	|	isakmpproposal_specs isakmpproposal_spec
907	;
908isakmpproposal_spec
909	:	STRENGTH
910		{
911			yyerror("strength directive is obsoleted.");
912		} STRENGTHTYPE EOS
913	|	LIFETIME LIFETYPE_TIME NUMBER unittype_time
914		{
915			prhead->spspec->lifetime = $3 * $4;
916		}
917		EOS
918	|	LIFETIME LIFETYPE_BYTE NUMBER unittype_byte
919		{
920#if 1
921			yyerror("byte lifetime support is deprecated");
922			return -1;
923#else
924			prhead->spspec->lifebyte = fix_lifebyte($3 * $4);
925			if (prhead->spspec->lifebyte == 0)
926				return -1;
927#endif
928		}
929		EOS
930	|	DH_GROUP dh_group_num
931		{
932			prhead->spspec->algclass[algclass_isakmp_dh] = $2;
933		}
934		EOS
935	|	GSSAPI_ID QUOTEDSTRING
936		{
937			if (prhead->spspec->vendorid != VENDORID_GSSAPI) {
938				yyerror("wrong Vendor ID for gssapi_id");
939				return -1;
940			}
941			prhead->spspec->gssid = strdup($2->v);
942		}
943		EOS
944	|	ALGORITHM_CLASS ALGORITHMTYPE keylength
945		{
946			int doi;
947			int defklen;
948
949			doi = algtype2doi($1, $2);
950			if (doi == -1) {
951				yyerror("algorithm mismatched 1");
952				return -1;
953			}
954
955			switch ($1) {
956			case algclass_isakmp_enc:
957			/* reject suppressed algorithms */
958#ifndef HAVE_OPENSSL_RC5_H
959				if ($2 == algtype_rc5) {
960					yyerror("algorithm %s not supported",
961					    s_attr_isakmp_enc(doi));
962					return -1;
963				}
964#endif
965#ifndef HAVE_OPENSSL_IDEA_H
966				if ($2 == algtype_idea) {
967					yyerror("algorithm %s not supported",
968					    s_attr_isakmp_enc(doi));
969					return -1;
970				}
971#endif
972
973				prhead->spspec->algclass[algclass_isakmp_enc] = doi;
974				defklen = default_keylen($1, $2);
975				if (defklen == 0) {
976					if ($3) {
977						yyerror("keylen not allowed");
978						return -1;
979					}
980				} else {
981					if ($3 && check_keylen($1, $2, $3) < 0) {
982						yyerror("invalid keylen %d", $3);
983						return -1;
984					}
985				}
986				if ($3)
987					prhead->spspec->encklen = $3;
988				else
989					prhead->spspec->encklen = defklen;
990				break;
991			case algclass_isakmp_hash:
992				prhead->spspec->algclass[algclass_isakmp_hash] = doi;
993				break;
994			case algclass_isakmp_ameth:
995				prhead->spspec->algclass[algclass_isakmp_ameth] = doi;
996				/*
997				 * We may have to set the Vendor ID for the
998				 * authentication method we're using.
999				 */
1000				switch ($2) {
1001				case algtype_gssapikrb:
1002					if (prhead->spspec->vendorid !=
1003					    VENDORID_UNKNOWN) {
1004						yyerror("Vendor ID mismatch "
1005						    "for auth method");
1006						return -1;
1007					}
1008					/*
1009					 * For interoperability with Win2k,
1010					 * we set the Vendor ID to "GSSAPI".
1011					 */
1012					prhead->spspec->vendorid =
1013					    VENDORID_GSSAPI;
1014					break;
1015				default:
1016					break;
1017				}
1018				break;
1019			default:
1020				yyerror("algorithm mismatched 2");
1021				return -1;
1022			}
1023		}
1024		EOS
1025	;
1026
1027unittype_time
1028	:	UNITTYPE_SEC	{ $$ = 1; }
1029	|	UNITTYPE_MIN	{ $$ = 60; }
1030	|	UNITTYPE_HOUR	{ $$ = (60 * 60); }
1031	;
1032unittype_byte
1033	:	UNITTYPE_BYTE	{ $$ = 1; }
1034	|	UNITTYPE_KBYTES	{ $$ = 1024; }
1035	|	UNITTYPE_MBYTES	{ $$ = (1024 * 1024); }
1036	|	UNITTYPE_TBYTES	{ $$ = (1024 * 1024 * 1024); }
1037	;
1038%%
1039
1040static struct proposalspec *
1041newprspec()
1042{
1043	struct proposalspec *new;
1044
1045	new = racoon_calloc(1, sizeof(*new));
1046	if (new == NULL)
1047		yyerror("failed to allocate proposal");
1048
1049	return new;
1050}
1051
1052static void
1053cleanprhead()
1054{
1055	struct proposalspec *p, *next;
1056
1057	if (prhead == NULL)
1058		return;
1059
1060	for (p = prhead; p != NULL; p = next) {
1061		next = p->next;
1062		racoon_free(p);
1063	}
1064
1065	prhead = NULL;
1066}
1067
1068/*
1069 * insert into head of list.
1070 */
1071static void
1072insprspec(prspec, head)
1073	struct proposalspec *prspec;
1074	struct proposalspec **head;
1075{
1076	if (*head != NULL)
1077		(*head)->prev = prspec;
1078	prspec->next = *head;
1079	*head = prspec;
1080}
1081
1082static struct secprotospec *
1083newspspec()
1084{
1085	struct secprotospec *new;
1086
1087	new = racoon_calloc(1, sizeof(*new));
1088	if (new == NULL) {
1089		yyerror("failed to allocate spproto");
1090		return NULL;
1091	}
1092
1093	new->encklen = 0;	/*XXX*/
1094
1095	/*
1096	 * Default to "uknown" vendor -- we will override this
1097	 * as necessary.  When we send a Vendor ID payload, an
1098	 * "unknown" will be translated to a KAME/racoon ID.
1099	 */
1100	new->vendorid = VENDORID_UNKNOWN;
1101
1102	return new;
1103}
1104
1105/*
1106 * insert into head of list.
1107 */
1108static void
1109insspspec(spspec, head)
1110	struct secprotospec *spspec;
1111	struct proposalspec **head;
1112{
1113	spspec->back = *head;
1114
1115	if ((*head)->spspec != NULL)
1116		(*head)->spspec->prev = spspec;
1117	spspec->next = (*head)->spspec;
1118	(*head)->spspec = spspec;
1119}
1120
1121/* set final acceptable proposal */
1122static int
1123set_isakmp_proposal(rmconf, prspec)
1124	struct remoteconf *rmconf;
1125	struct proposalspec *prspec;
1126{
1127	struct proposalspec *p;
1128	struct secprotospec *s;
1129	int prop_no = 1;
1130	int trns_no = 1;
1131	u_int32_t types[MAXALGCLASS];
1132
1133	p = prspec;
1134	if (p->next != 0) {
1135		plog(LLV_ERROR, LOCATION, NULL,
1136			"multiple proposal definition.\n");
1137		return -1;
1138	}
1139
1140	/* mandatory check */
1141	if (p->spspec == NULL) {
1142		yyerror("no remote specification found: %s.\n",
1143			rm2str(rmconf));
1144		return -1;
1145	}
1146	for (s = p->spspec; s != NULL; s = s->next) {
1147		/* XXX need more to check */
1148		if (s->algclass[algclass_isakmp_enc] == 0) {
1149			yyerror("encryption algorithm required.");
1150			return -1;
1151		}
1152		if (s->algclass[algclass_isakmp_hash] == 0) {
1153			yyerror("hash algorithm required.");
1154			return -1;
1155		}
1156		if (s->algclass[algclass_isakmp_dh] == 0) {
1157			yyerror("DH group required.");
1158			return -1;
1159		}
1160		if (s->algclass[algclass_isakmp_ameth] == 0) {
1161			yyerror("authentication method required.");
1162			return -1;
1163		}
1164	}
1165
1166	/* skip to last part */
1167	for (s = p->spspec; s->next != NULL; s = s->next)
1168		;
1169
1170	while (s != NULL) {
1171		plog(LLV_DEBUG2, LOCATION, NULL,
1172			"lifetime = %ld\n", (long)
1173			(s->lifetime ? s->lifetime : p->lifetime));
1174		plog(LLV_DEBUG2, LOCATION, NULL,
1175			"lifebyte = %d\n",
1176			s->lifebyte ? s->lifebyte : p->lifebyte);
1177		plog(LLV_DEBUG2, LOCATION, NULL,
1178			"encklen=%d\n", s->encklen);
1179
1180		memset(types, 0, ARRAYLEN(types));
1181		types[algclass_isakmp_enc] = s->algclass[algclass_isakmp_enc];
1182		types[algclass_isakmp_hash] = s->algclass[algclass_isakmp_hash];
1183		types[algclass_isakmp_dh] = s->algclass[algclass_isakmp_dh];
1184		types[algclass_isakmp_ameth] =
1185		    s->algclass[algclass_isakmp_ameth];
1186
1187		/* expanding spspec */
1188		clean_tmpalgtype();
1189		trns_no = expand_isakmpspec(prop_no, trns_no, types,
1190				algclass_isakmp_enc, algclass_isakmp_ameth + 1,
1191				s->lifetime ? s->lifetime : p->lifetime,
1192				s->lifebyte ? s->lifebyte : p->lifebyte,
1193				s->encklen, s->vendorid, s->gssid,
1194				rmconf);
1195		if (trns_no == -1) {
1196			plog(LLV_ERROR, LOCATION, NULL,
1197				"failed to expand isakmp proposal.\n");
1198			return -1;
1199		}
1200
1201		s = s->prev;
1202	}
1203
1204	if (rmconf->proposal == NULL) {
1205		plog(LLV_ERROR, LOCATION, NULL,
1206			"no proposal found.\n");
1207		return -1;
1208	}
1209
1210	return 0;
1211}
1212
1213static void
1214clean_tmpalgtype()
1215{
1216	int i;
1217	for (i = 0; i < MAXALGCLASS; i++)
1218		tmpalgtype[i] = 0;	/* means algorithm undefined. */
1219}
1220
1221static int
1222expand_isakmpspec(prop_no, trns_no, types,
1223		class, last, lifetime, lifebyte, encklen, vendorid, gssid,
1224		rmconf)
1225	int prop_no, trns_no;
1226	int *types, class, last;
1227	time_t lifetime;
1228	int lifebyte;
1229	int encklen;
1230	int vendorid;
1231	char *gssid;
1232	struct remoteconf *rmconf;
1233{
1234	struct isakmpsa *new;
1235
1236	/* debugging */
1237    {
1238	int j;
1239	char tb[10];
1240	plog(LLV_DEBUG2, LOCATION, NULL,
1241		"p:%d t:%d\n", prop_no, trns_no);
1242	for (j = class; j < MAXALGCLASS; j++) {
1243		snprintf(tb, sizeof(tb), "%d", types[j]);
1244		plog(LLV_DEBUG2, LOCATION, NULL,
1245			"%s%s%s%s\n",
1246			s_algtype(j, types[j]),
1247			types[j] ? "(" : "",
1248			tb[0] == '0' ? "" : tb,
1249			types[j] ? ")" : "");
1250	}
1251	plog(LLV_DEBUG2, LOCATION, NULL, "\n");
1252    }
1253
1254#define TMPALGTYPE2STR(n) \
1255	s_algtype(algclass_isakmp_##n, types[algclass_isakmp_##n])
1256		/* check mandatory values */
1257		if (types[algclass_isakmp_enc] == 0
1258		 || types[algclass_isakmp_ameth] == 0
1259		 || types[algclass_isakmp_hash] == 0
1260		 || types[algclass_isakmp_dh] == 0) {
1261			yyerror("few definition of algorithm "
1262				"enc=%s ameth=%s hash=%s dhgroup=%s.\n",
1263				TMPALGTYPE2STR(enc),
1264				TMPALGTYPE2STR(ameth),
1265				TMPALGTYPE2STR(hash),
1266				TMPALGTYPE2STR(dh));
1267			return -1;
1268		}
1269#undef TMPALGTYPE2STR
1270
1271	/* set new sa */
1272	new = newisakmpsa();
1273	if (new == NULL) {
1274		yyerror("failed to allocate isakmp sa");
1275		return -1;
1276	}
1277	new->prop_no = prop_no;
1278	new->trns_no = trns_no++;
1279	new->lifetime = lifetime;
1280	new->lifebyte = lifebyte;
1281	new->enctype = types[algclass_isakmp_enc];
1282	new->encklen = encklen;
1283	new->authmethod = types[algclass_isakmp_ameth];
1284	new->hashtype = types[algclass_isakmp_hash];
1285	new->dh_group = types[algclass_isakmp_dh];
1286	new->vendorid = vendorid;
1287#ifdef HAVE_GSSAPI
1288	if (gssid != NULL) {
1289		new->gssid = vmalloc(strlen(gssid) + 1);
1290		memcpy(new->gssid->v, gssid, new->gssid->l);
1291		racoon_free(gssid);
1292	} else
1293		new->gssid = NULL;
1294#endif
1295	insisakmpsa(new, rmconf);
1296
1297	return trns_no;
1298}
1299
1300#if 0
1301/*
1302 * fix lifebyte.
1303 * Must be more than 1024B because its unit is kilobytes.
1304 * That is defined RFC2407.
1305 */
1306static int
1307fix_lifebyte(t)
1308	unsigned long t;
1309{
1310	if (t < 1024) {
1311		yyerror("byte size should be more than 1024B.");
1312		return 0;
1313	}
1314
1315	return(t / 1024);
1316}
1317#endif
1318
1319int
1320cfparse()
1321{
1322	int error;
1323
1324	yycf_init_buffer();
1325
1326	if (yycf_set_buffer(lcconf->racoon_conf) != 0)
1327		return -1;
1328
1329	prhead = NULL;
1330
1331	error = yyparse();
1332	if (error != 0) {
1333		if (yyerrorcount) {
1334			plog(LLV_ERROR, LOCATION, NULL,
1335				"fatal parse failure (%d errors)\n",
1336				yyerrorcount);
1337		} else {
1338			plog(LLV_ERROR, LOCATION, NULL,
1339				"fatal parse failure.\n");
1340		}
1341		return -1;
1342	}
1343
1344	if (error == 0 && yyerrorcount) {
1345		plog(LLV_ERROR, LOCATION, NULL,
1346			"parse error is nothing, but yyerrorcount is %d.\n",
1347				yyerrorcount);
1348		exit(1);
1349	}
1350
1351	yycf_clean_buffer();
1352
1353	plog(LLV_DEBUG2, LOCATION, NULL, "parse successed.\n");
1354
1355	return 0;
1356}
1357
1358int
1359cfreparse()
1360{
1361	flushph2();
1362	flushph1();
1363	flushrmconf();
1364	cleanprhead();
1365	clean_tmpalgtype();
1366	yycf_init_buffer();
1367
1368	if (yycf_set_buffer(lcconf->racoon_conf) != 0)
1369		return -1;
1370
1371	return(cfparse());
1372}
1373
1374