parse.y revision 1.27
1/*	$OpenBSD: parse.y,v 1.27 2005/10/16 21:29:22 hshoexer Exp $	*/
2
3/*
4 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 2001 Markus Friedl.  All rights reserved.
6 * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
7 * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
8 * Copyright (c) 2004, 2005 Hans-Joerg Hoexer <hshoexer@openbsd.org>
9 *
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
23%{
24#include <sys/types.h>
25#include <sys/queue.h>
26#include <sys/socket.h>
27#include <sys/stat.h>
28#include <netinet/in.h>
29#include <netinet/ip_ipsp.h>
30#include <arpa/inet.h>
31
32#include <ctype.h>
33#include <err.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <limits.h>
37#include <stdarg.h>
38#include <stdio.h>
39#include <string.h>
40#include <syslog.h>
41#include <unistd.h>
42
43#include "ipsecctl.h"
44
45#define KEYSIZE_LIMIT	1024
46
47static struct ipsecctl	*ipsec = NULL;
48static FILE		*fin = NULL;
49static int		 lineno = 1;
50static int		 errors = 0;
51static int		 debug = 0;
52
53const struct ipsec_xf authxfs[] = {
54	{"unknown",		AUTHXF_UNKNOWN,		0,	0},
55	{"none",		AUTHXF_NONE,		0,	0},
56	{"hmac-md5",		AUTHXF_HMAC_MD5,	16,	0},
57	{"hmac-ripemd160",	AUTHXF_HMAC_RIPEMD160,	20,	0},
58	{"hmac-sha1",		AUTHXF_HMAC_SHA1,	20,	0},
59	{"hmac-sha2-256",	AUTHXF_HMAC_SHA2_256,	32,	0},
60	{"hmac-sha2-384",	AUTHXF_HMAC_SHA2_384,	48,	0},
61	{"hmac-sha2-512",	AUTHXF_HMAC_SHA2_512,	64,	0},
62	{"md5",			AUTHXF_MD5,		16,	0},
63	{"sha1",		AUTHXF_SHA1,		20,	0},
64	{NULL,			0,			0,	0},
65};
66
67const struct ipsec_xf encxfs[] = {
68	{"unknown",		ENCXF_UNKNOWN,		0,	0},
69	{"none",		ENCXF_NONE,		0,	0},
70	{"3des-cbc",		ENCXF_3DES_CBC,		24,	24},
71	{"des-cbc",		ENCXF_DES_CBC,		8,	8},
72	{"aes",			ENCXF_AES,		16,	32},
73	{"aesctr",		ENCXF_AESCTR,		16+4,	32+4},
74	{"blowfish",		ENCXF_BLOWFISH,		5,	56},
75	{"cast128",		ENCXF_CAST128,		5,	16},
76	{"null",		ENCXF_NULL,		0,	0},
77	{"skipjack",		ENCXF_SKIPJACK,		10,	10},
78	{NULL,			0,			0,	0},
79};
80
81int			 yyerror(const char *, ...);
82int			 yyparse(void);
83int			 kw_cmp(const void *, const void *);
84int			 lookup(char *);
85int			 lgetc(FILE *);
86int			 lungetc(int);
87int			 findeol(void);
88int			 yylex(void);
89
90TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
91struct sym {
92	TAILQ_ENTRY(sym)	 entries;
93	int		 used;
94	int		 persist;
95	char		*nam;
96	char		*val;
97};
98
99int			 symset(const char *, const char *, int);
100int			 cmdline_symset(char *);
101char			*symget(const char *);
102int			 atoul(char *, u_long *);
103int			 atospi(char *, u_int32_t *);
104u_int8_t		 x2i(unsigned char *);
105struct ipsec_key	*parsekey(unsigned char *, size_t);
106struct ipsec_key	*parsekeyfile(char *);
107struct ipsec_addr	*host(const char *);
108struct ipsec_addr	*copyhost(const struct ipsec_addr *);
109const struct ipsec_xf	*parse_xf(const char *, const struct ipsec_xf *);
110struct ipsec_transforms *transforms(const char *, const char *);
111struct ipsec_transforms *copytransforms(const struct ipsec_transforms *);
112int			 validate_sa(u_int32_t, u_int8_t,
113			     struct ipsec_transforms *, struct ipsec_key *,
114			     struct ipsec_key *);
115struct ipsec_rule	*create_sa(u_int8_t, struct ipsec_addr *,
116			     struct ipsec_addr *, u_int32_t,
117			     struct ipsec_transforms *, struct ipsec_key *,
118			     struct ipsec_key *);
119struct ipsec_rule	*reverse_sa(struct ipsec_rule *, u_int32_t,
120			     struct ipsec_key *, struct ipsec_key *);
121struct ipsec_rule	*create_flow(u_int8_t, struct ipsec_addr *, struct
122			     ipsec_addr *, struct ipsec_addr *, u_int8_t,
123			     char *, char *, u_int16_t);
124struct ipsec_rule	*reverse_rule(struct ipsec_rule *);
125struct ipsec_rule	*create_ike(struct ipsec_addr *, struct ipsec_addr *,
126			     struct ipsec_addr *, struct ipsec_transforms *,
127			     struct ipsec_transforms *, u_int8_t, u_int8_t,
128			     char *, char *);
129
130typedef struct {
131	union {
132		u_int32_t	 number;
133		u_int8_t	 ikemode;
134		u_int8_t	 dir;
135		char		*string;
136		u_int8_t	 protocol;
137		struct {
138			struct ipsec_addr *src;
139			struct ipsec_addr *dst;
140		} hosts;
141		struct ipsec_addr *peer;
142		struct ipsec_addr *host;
143		struct {
144			char *srcid;
145			char *dstid;
146		} ids;
147		char		*id;
148		u_int16_t	 authtype;
149		struct {
150			u_int32_t	spiout;
151			u_int32_t	spiin;
152		} spis;
153		struct {
154			struct ipsec_key *keyout;
155			struct ipsec_key *keyin;
156		} authkeys;
157		struct {
158			struct ipsec_key *keyout;
159			struct ipsec_key *keyin;
160		} enckeys;
161		struct {
162			struct ipsec_key *keyout;
163			struct ipsec_key *keyin;
164		} keys;
165		struct ipsec_transforms *transforms;
166		struct ipsec_transforms *mmxfs;
167		struct ipsec_transforms *qmxfs;
168	} v;
169	int lineno;
170} YYSTYPE;
171
172%}
173
174%token	FLOW FROM ESP AH IN PEER ON OUT TO SRCID DSTID RSA PSK TCPMD5 SPI
175%token	AUTHKEY ENCKEY FILENAME AUTHXF ENCXF ERROR IKE MAIN QUICK PASSIVE
176%token	ACTIVE ANY
177%token	<v.string>		STRING
178%type	<v.dir>			dir
179%type	<v.protocol>		protocol
180%type	<v.number>		number
181%type	<v.hosts>		hosts
182%type	<v.peer>		peer
183%type	<v.host>		host
184%type	<v.ids>			ids
185%type	<v.id>			id
186%type	<v.authtype>		authtype
187%type	<v.spis>		spispec
188%type	<v.authkeys>		authkeyspec
189%type	<v.enckeys>		enckeyspec
190%type	<v.keys>		keyspec
191%type	<v.transforms>		transforms
192%type	<v.mmxfs>		mmxfs
193%type	<v.qmxfs>		qmxfs
194%type	<v.ikemode>		ikemode
195%%
196
197grammar		: /* empty */
198		| grammar '\n'
199		| grammar ikerule '\n'
200		| grammar flowrule '\n'
201		| grammar sarule '\n'
202		| grammar tcpmd5rule '\n'
203		| grammar error '\n'		{ errors++; }
204		;
205
206number		: STRING			{
207			unsigned long	ulval;
208
209			if (atoul($1, &ulval) == -1) {
210				yyerror("%s is not a number", $1);
211				free($1);
212				YYERROR;
213			}
214			if (ulval > UINT_MAX) {
215				yyerror("0x%lx out of range", ulval);
216				free($1);
217				YYERROR;
218			}
219			$$ = (u_int32_t)ulval;
220			free($1);
221		}
222		;
223
224tcpmd5rule	: TCPMD5 hosts spispec authkeyspec	{
225			struct ipsec_rule	*r;
226
227			r = create_sa(IPSEC_TCPMD5, $2.src, $2.dst, $3.spiout,
228			    NULL, $4.keyout, NULL);
229			if (r == NULL)
230				YYERROR;
231			r->nr = ipsec->rule_nr++;
232
233			if (ipsecctl_add_rule(ipsec, r))
234				errx(1, "tcpmd5rule: ipsecctl_add_rule");
235
236			/* Create and add reverse SA rule. */
237			if ($3.spiin != 0 || $4.keyin != NULL) {
238				r = reverse_sa(r, $3.spiin, $4.keyin, NULL);
239				if (r == NULL)
240					YYERROR;
241				r->nr = ipsec->rule_nr++;
242
243				if (ipsecctl_add_rule(ipsec, r))
244					errx(1, "tcpmd5rule: ipsecctl_add_rule");
245			}
246		}
247		;
248
249sarule		: protocol hosts spispec transforms authkeyspec enckeyspec {
250			struct ipsec_rule	*r;
251
252			r = create_sa($1, $2.src, $2.dst, $3.spiout, $4,
253			    $5.keyout, $6.keyout);
254			if (r == NULL)
255				YYERROR;
256			r->nr = ipsec->rule_nr++;
257
258			if (ipsecctl_add_rule(ipsec, r))
259				errx(1, "sarule: ipsecctl_add_rule");
260
261			/* Create and add reverse SA rule. */
262			if ($3.spiin != 0 || $5.keyin || $6.keyin) {
263				r = reverse_sa(r, $3.spiin, $5.keyin,
264				    $6.keyin);
265				if (r == NULL)
266					YYERROR;
267				r->nr = ipsec->rule_nr++;
268
269				if (ipsecctl_add_rule(ipsec, r))
270					errx(1, "sarule: ipsecctl_add_rule");
271			}
272		}
273		;
274
275flowrule	: FLOW protocol dir hosts peer ids authtype	{
276			struct ipsec_rule	*r;
277
278			r = create_flow($3, $4.src, $4.dst, $5, $2, $6.srcid,
279			    $6.dstid, $7);
280			if (r == NULL)
281				YYERROR;
282			r->nr = ipsec->rule_nr++;
283
284			if (ipsecctl_add_rule(ipsec, r))
285				errx(1, "flowrule: ipsecctl_add_rule");
286
287			/* Create and add reverse flow rule. */
288			if ($3 == IPSEC_INOUT) {
289				r = reverse_rule(r);
290				r->nr = ipsec->rule_nr++;
291
292				if (ipsecctl_add_rule(ipsec, r))
293					errx(1, "flowrule: ipsecctl_add_rule");
294			}
295		}
296		;
297
298ikerule		: IKE ikemode protocol hosts peer mmxfs qmxfs ids {
299			struct ipsec_rule	*r;
300
301			r = create_ike($4.src, $4.dst, $5, $6, $7, $3, $2,
302			    $8.srcid, $8.dstid);
303			if (r == NULL)
304				YYERROR;
305			r->nr = ipsec->rule_nr++;
306
307			if (ipsecctl_add_rule(ipsec, r))
308				errx(1, "ikerule: ipsecctl_add_rule");
309		};
310
311protocol	: /* empty */			{ $$ = IPSEC_ESP; }
312		| ESP				{ $$ = IPSEC_ESP; }
313		| AH				{ $$ = IPSEC_AH; }
314		;
315
316dir		: /* empty */			{ $$ = IPSEC_INOUT; }
317		| IN				{ $$ = IPSEC_IN; }
318		| OUT				{ $$ = IPSEC_OUT; }
319		;
320
321hosts		: FROM host TO host		{
322			$$.src = $2;
323			$$.dst = $4;
324		}
325		;
326
327peer		: /* empty */			{ $$ = NULL; }
328		| PEER STRING			{
329			if (($$ = host($2)) == NULL) {
330				free($2);
331				yyerror("could not parse host specification");
332				YYERROR;
333			}
334			free($2);
335		}
336		;
337
338host		: STRING			{
339			if (($$ = host($1)) == NULL) {
340				free($1);
341				yyerror("could not parse host specification");
342				YYERROR;
343			}
344			free($1);
345		}
346		| STRING '/' number		{
347			char	*buf;
348
349			if (asprintf(&buf, "%s/%u", $1, $3) == -1)
350				err(1, "host: asprintf");
351			free($1);
352			if (($$ = host(buf)) == NULL)	{
353				free(buf);
354				yyerror("could not parse host specification");
355				YYERROR;
356			}
357			free(buf);
358		}
359		| ANY				{
360			struct ipsec_addr	*ipa;
361
362			ipa = calloc(1, sizeof(struct ipsec_addr));
363			if (ipa == NULL)
364				err(1, "calloc");
365
366			ipa->af = AF_INET;
367			ipa->netaddress = 1;
368			if ((ipa->name = strdup("0.0.0.0/0")) == NULL)
369				err(1, "strdup");
370			$$ = ipa;
371		}
372		;
373
374ids		: /* empty */			{
375			$$.srcid = NULL;
376			$$.dstid = NULL;
377		}
378		| SRCID id DSTID id		{
379			$$.srcid = $2;
380			$$.dstid = $4;
381		}
382		| SRCID id			{
383			$$.srcid = $2;
384			$$.dstid = NULL;
385		}
386		| DSTID id			{
387			$$.srcid = NULL;
388			$$.dstid = $2;
389		}
390		;
391
392id		: STRING			{ $$ = $1; }
393		;
394
395authtype	: /* empty */			{ $$ = 0; }
396		| RSA				{ $$ = AUTH_RSA; }
397		| PSK				{ $$ = AUTH_PSK; }
398		;
399
400spispec		: SPI STRING			{
401			u_int32_t	 spi;
402			char		*p = strchr($2, ':');
403
404			if (p != NULL) {
405				*p++ = 0;
406
407				if (atospi(p, &spi) == -1) {
408					yyerror("%s is not a valid spi", p);
409					free($2);
410					YYERROR;
411				}
412				$$.spiin = spi;
413			}
414			if (atospi($2, &spi) == -1) {
415				yyerror("%s is not a valid spi", $2);
416				free($2);
417				YYERROR;
418			}
419			$$.spiout = spi;
420
421
422			free($2);
423		}
424		;
425
426transforms	: /* empty */			{
427			struct ipsec_transforms *xfs;
428
429			/* We create just an empty transform */
430			if ((xfs = calloc(1, sizeof(struct ipsec_transforms)))
431			    == NULL)
432				err(1, "transforms: calloc");
433			$$ = xfs;
434		}
435		| AUTHXF STRING ENCXF STRING	{
436			if (($$ = transforms($2, $4)) == NULL) {
437				free($2);
438				free($4);
439				yyerror("could not parse transforms");
440				YYERROR;
441			}
442			free($2);
443			free($4);
444		}
445		| AUTHXF STRING			{
446			if (($$ = transforms($2, NULL)) == NULL) {
447				free($2);
448				yyerror("could not parse transforms");
449				YYERROR;
450			}
451			free($2);
452		}
453		| ENCXF STRING			{
454			if (($$ = transforms(NULL, $2)) == NULL) {
455				free($2);
456				yyerror("could not parse transforms");
457				YYERROR;
458			}
459			free($2);
460		}
461		;
462
463mmxfs		: /* empty */			{
464			struct ipsec_transforms *xfs;
465
466			/* We create just an empty transform */
467			if ((xfs = calloc(1, sizeof(struct ipsec_transforms)))
468			    == NULL)
469				err(1, "mmxfs: calloc");
470			$$ = xfs;
471		}
472		| MAIN transforms		{ $$ = $2; }
473		;
474
475qmxfs		: /* empty */			{
476			struct ipsec_transforms *xfs;
477
478			/* We create just an empty transform */
479			if ((xfs = calloc(1, sizeof(struct ipsec_transforms)))
480			    == NULL)
481				err(1, "qmxfs: calloc");
482			$$ = xfs;
483		}
484		| QUICK transforms		{ $$ = $2; }
485		;
486
487authkeyspec	: /* empty */			{
488			$$.keyout = NULL;
489			$$.keyin = NULL;
490		}
491		| AUTHKEY keyspec		{
492			$$.keyout = $2.keyout;
493			$$.keyin = $2.keyin;
494		}
495		;
496
497enckeyspec	: /* empty */			{
498			$$.keyout = NULL;
499			$$.keyin = NULL;
500		}
501		| ENCKEY keyspec		{
502			$$.keyout = $2.keyout;
503			$$.keyin = $2.keyin;
504		}
505		;
506
507keyspec		: STRING			{
508			unsigned char	*hex;
509			unsigned char	*p = strchr($1, ':');
510
511			if (p != NULL ) {
512				*p++ = 0;
513
514				if (!strncmp(p, "0x", 2))
515					p += 2;
516				$$.keyin = parsekey(p, strlen(p));
517			}
518
519			hex = $1;
520			if (!strncmp(hex, "0x", 2))
521				hex += 2;
522			$$.keyout = parsekey(hex, strlen(hex));
523
524			free($1);
525		}
526		| FILENAME STRING		{
527			unsigned char	*p = strchr($2, ':');
528
529			if (p != NULL) {
530				*p++ = 0;
531				$$.keyin = parsekeyfile(p);
532			}
533			$$.keyout = parsekeyfile($2);
534			free($2);
535		}
536		;
537ikemode		: /* empty */			{ $$ = IKE_ACTIVE; }
538		| PASSIVE			{ $$ = IKE_PASSIVE; }
539		| ACTIVE			{ $$ = IKE_ACTIVE; }
540		;
541%%
542
543struct keywords {
544	const char	*k_name;
545	int		 k_val;
546};
547
548int
549yyerror(const char *fmt, ...)
550{
551	va_list		 ap;
552	extern char 	*infile;
553
554	errors = 1;
555	va_start(ap, fmt);
556	fprintf(stderr, "%s: %d: ", infile, yyval.lineno);
557	vfprintf(stderr, fmt, ap);
558	fprintf(stderr, "\n");
559	va_end(ap);
560	return (0);
561}
562
563int
564kw_cmp(const void *k, const void *e)
565{
566	return (strcmp(k, ((const struct keywords *)e)->k_name));
567}
568
569int
570lookup(char *s)
571{
572	/* this has to be sorted always */
573	static const struct keywords keywords[] = {
574		{ "active",		ACTIVE},
575		{ "ah",			AH},
576		{ "any",		ANY},
577		{ "auth",		AUTHXF},
578		{ "authkey",		AUTHKEY},
579		{ "dstid",		DSTID},
580		{ "enc",		ENCXF},
581		{ "enckey",		ENCKEY},
582		{ "esp",		ESP},
583		{ "file",		FILENAME},
584		{ "flow",		FLOW},
585		{ "from",		FROM},
586		{ "ike",		IKE},
587		{ "in",			IN},
588		{ "main",		MAIN},
589		{ "out",		OUT},
590		{ "passive",		PASSIVE},
591		{ "peer",		PEER},
592		{ "psk",		PSK},
593		{ "quick",		QUICK},
594		{ "rsa",		RSA},
595		{ "spi",		SPI},
596		{ "srcid",		SRCID},
597		{ "tcpmd5",		TCPMD5},
598		{ "to",			TO},
599	};
600	const struct keywords	*p;
601
602	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
603	    sizeof(keywords[0]), kw_cmp);
604
605	if (p) {
606		if (debug > 1)
607			fprintf(stderr, "%s: %d\n", s, p->k_val);
608		return (p->k_val);
609	} else {
610		if (debug > 1)
611			fprintf(stderr, "string: %s\n", s);
612		return (STRING);
613	}
614}
615
616#define MAXPUSHBACK	128
617
618char	*parsebuf;
619int	 parseindex;
620char	 pushback_buffer[MAXPUSHBACK];
621int	 pushback_index = 0;
622
623int
624lgetc(FILE *f)
625{
626	int	c, next;
627
628	if (parsebuf) {
629		/* Read character from the parsebuffer instead of input. */
630		if (parseindex >= 0) {
631			c = parsebuf[parseindex++];
632			if (c != '\0')
633				return (c);
634			parsebuf = NULL;
635		} else
636			parseindex++;
637	}
638
639	if (pushback_index)
640		return (pushback_buffer[--pushback_index]);
641
642	while ((c = getc(f)) == '\\') {
643		next = getc(f);
644		if (next != '\n') {
645			if (isspace(next))
646				yyerror("whitespace after \\");
647			ungetc(next, f);
648			break;
649		}
650		yylval.lineno = lineno;
651		lineno++;
652	}
653	if (c == '\t' || c == ' ') {
654		/* Compress blanks to a single space. */
655		do {
656			c = getc(f);
657		} while (c == '\t' || c == ' ');
658		ungetc(c, f);
659		c = ' ';
660	}
661
662	return (c);
663}
664
665int
666lungetc(int c)
667{
668	if (c == EOF)
669		return (EOF);
670	if (parsebuf) {
671		parseindex--;
672		if (parseindex >= 0)
673			return (c);
674	}
675	if (pushback_index < MAXPUSHBACK-1)
676		return (pushback_buffer[pushback_index++] = c);
677	else
678		return (EOF);
679}
680
681int
682findeol(void)
683{
684	int	c;
685
686	parsebuf = NULL;
687	pushback_index = 0;
688
689	/* skip to either EOF or the first real EOL */
690	while (1) {
691		c = lgetc(fin);
692		if (c == '\n') {
693			lineno++;
694			break;
695		}
696		if (c == EOF)
697			break;
698	}
699	return (ERROR);
700}
701
702int
703yylex(void)
704{
705	char	 buf[8096];
706	char	*p, *val;
707	int	 endc, c;
708	int	 token;
709
710top:
711	p = buf;
712	while ((c = lgetc(fin)) == ' ')
713		; /* nothing */
714
715	yylval.lineno = lineno;
716	if (c == '#')
717		while ((c = lgetc(fin)) != '\n' && c != EOF)
718			; /* nothing */
719	if (c == '$' && parsebuf == NULL) {
720		while (1) {
721			if ((c = lgetc(fin)) == EOF)
722				return (0);
723
724			if (p + 1 >= buf + sizeof(buf) - 1) {
725				yyerror("string too long");
726				return (findeol());
727			}
728			if (isalnum(c) || c == '_') {
729				*p++ = (char)c;
730				continue;
731			}
732			*p = '\0';
733			lungetc(c);
734			break;
735		}
736		val = symget(buf);
737		if (val == NULL) {
738			yyerror("macro \"%s\" not defined", buf);
739			return (findeol());
740		}
741		parsebuf = val;
742		parseindex = 0;
743		goto top;
744	}
745
746	switch (c) {
747	case '\'':
748	case '"':
749		endc = c;
750		while (1) {
751			if ((c = lgetc(fin)) == EOF)
752				return (0);
753			if (c == endc) {
754				*p = '\0';
755				break;
756			}
757			if (c == '\n') {
758				lineno++;
759				continue;
760			}
761			if (p + 1 >= buf + sizeof(buf) - 1) {
762				yyerror("string too long");
763				return (findeol());
764			}
765			*p++ = (char)c;
766		}
767		yylval.v.string = strdup(buf);
768		if (yylval.v.string == NULL)
769			err(1, "yylex: strdup");
770		return (STRING);
771	}
772
773#define allowed_in_string(x) \
774	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
775	x != '{' && x != '}' && x != '<' && x != '>' && \
776	x != '!' && x != '=' && x != '/' && x != '#' && \
777	x != ','))
778
779	if (isalnum(c) || c == ':' || c == '_' || c == '*') {
780		do {
781			*p++ = c;
782			if ((unsigned)(p-buf) >= sizeof(buf)) {
783				yyerror("string too long");
784				return (findeol());
785			}
786		} while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
787		lungetc(c);
788		*p = '\0';
789		if ((token = lookup(buf)) == STRING)
790			if ((yylval.v.string = strdup(buf)) == NULL)
791				err(1, "yylex: strdup");
792		return (token);
793	}
794	if (c == '\n') {
795		yylval.lineno = lineno;
796		lineno++;
797	}
798	if (c == EOF)
799		return (0);
800	return (c);
801}
802
803int
804parse_rules(FILE *input, struct ipsecctl *ipsecx)
805{
806	struct sym	*sym, *next;
807
808	ipsec = ipsecx;
809	fin = input;
810	lineno = 1;
811	errors = 0;
812
813	yyparse();
814
815	/* Free macros and check which have not been used. */
816	for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
817		next = TAILQ_NEXT(sym, entries);
818		free(sym->nam);
819		free(sym->val);
820		TAILQ_REMOVE(&symhead, sym, entries);
821		free(sym);
822	}
823
824	return (errors ? -1 : 0);
825}
826
827int
828symset(const char *nam, const char *val, int persist)
829{
830	struct sym	*sym;
831
832	for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
833	    sym = TAILQ_NEXT(sym, entries))
834		;	/* nothing */
835
836	if (sym != NULL) {
837		if (sym->persist == 1)
838			return (0);
839		else {
840			free(sym->nam);
841			free(sym->val);
842			TAILQ_REMOVE(&symhead, sym, entries);
843			free(sym);
844		}
845	}
846	if ((sym = calloc(1, sizeof(*sym))) == NULL)
847		return (-1);
848
849	sym->nam = strdup(nam);
850	if (sym->nam == NULL) {
851		free(sym);
852		return (-1);
853	}
854	sym->val = strdup(val);
855	if (sym->val == NULL) {
856		free(sym->nam);
857		free(sym);
858		return (-1);
859	}
860	sym->used = 0;
861	sym->persist = persist;
862	TAILQ_INSERT_TAIL(&symhead, sym, entries);
863	return (0);
864}
865
866int
867cmdline_symset(char *s)
868{
869	char	*sym, *val;
870	int	ret;
871	size_t	len;
872
873	if ((val = strrchr(s, '=')) == NULL)
874		return (-1);
875
876	len = strlen(s) - strlen(val) + 1;
877	if ((sym = malloc(len)) == NULL)
878		err(1, "cmdline_symset: malloc");
879
880	strlcpy(sym, s, len);
881
882	ret = symset(sym, val + 1, 1);
883	free(sym);
884
885	return (ret);
886}
887
888char *
889symget(const char *nam)
890{
891	struct sym	*sym;
892
893	TAILQ_FOREACH(sym, &symhead, entries)
894		if (strcmp(nam, sym->nam) == 0) {
895			sym->used = 1;
896			return (sym->val);
897		}
898	return (NULL);
899}
900
901int
902atoul(char *s, u_long *ulvalp)
903{
904	u_long	 ulval;
905	char	*ep;
906
907	errno = 0;
908	ulval = strtoul(s, &ep, 0);
909	if (s[0] == '\0' || *ep != '\0')
910		return (-1);
911	if (errno == ERANGE && ulval == ULONG_MAX)
912		return (-1);
913	*ulvalp = ulval;
914	return (0);
915}
916
917int
918atospi(char *s, u_int32_t *spivalp)
919{
920	unsigned long	ulval;
921
922	if (atoul(s, &ulval) == -1)
923		return (-1);
924	if (ulval >= SPI_RESERVED_MIN && ulval <= SPI_RESERVED_MAX) {
925		yyerror("illegal SPI value");
926		return (-1);
927	}
928	*spivalp = ulval;
929	return (0);
930}
931
932u_int8_t
933x2i(unsigned char *s)
934{
935	char	ss[3];
936
937	ss[0] = s[0];
938	ss[1] = s[1];
939	ss[2] = 0;
940
941	if (!isxdigit(s[0]) || !isxdigit(s[1])) {
942		yyerror("keys need to be specified in hex digits");
943		return (-1);
944	}
945	return ((u_int8_t)strtoul(ss, NULL, 16));
946}
947
948struct ipsec_key *
949parsekey(unsigned char *hexkey, size_t len)
950{
951	struct ipsec_key *key;
952	int		  i;
953
954	key = calloc(1, sizeof(struct ipsec_key));
955	if (key == NULL)
956		err(1, "parsekey: calloc");
957
958	key->len = len / 2;
959	key->data = calloc(key->len, sizeof(u_int8_t));
960	if (key->data == NULL)
961		err(1, "parsekey: calloc");
962
963	for (i = 0; i < (int)key->len; i++)
964		key->data[i] = x2i(hexkey + 2 * i);
965
966	return (key);
967}
968
969struct ipsec_key *
970parsekeyfile(char *filename)
971{
972	struct stat	 sb;
973	int		 fd;
974	unsigned char	*hex;
975
976	if (stat(filename, &sb) < 0)
977		err(1, "parsekeyfile: stat %s", filename);
978	if ((sb.st_size > KEYSIZE_LIMIT) || (sb.st_size == 0))
979		errx(1, "key too %s", sb.st_size ? "large" :
980		    "small");
981	if ((hex = calloc(sb.st_size, sizeof(unsigned char)))
982	    == NULL)
983		err(1, "parsekeyfile: calloc");
984	if ((fd = open(filename, O_RDONLY)) < 0)
985		err(1, "parsekeyfile: open");
986	if (read(fd, hex, sb.st_size) < sb.st_size)
987		err(1, "parsekeyfile: read");
988	close(fd);
989	return (parsekey(hex, sb.st_size));
990}
991
992struct ipsec_addr *
993host(const char *s)
994{
995	struct ipsec_addr	*ipa;
996	int			 i, bits = 32;
997
998	/* XXX for now only AF_INET. */
999
1000	ipa = calloc(1, sizeof(struct ipsec_addr));
1001	if (ipa == NULL)
1002		err(1, "host: calloc");
1003
1004	if ((ipa->name = strdup(s)) == NULL)
1005		err(1, "host: strdup");
1006
1007	if (strrchr(s, '/') != NULL) {
1008		bits = inet_net_pton(AF_INET, s, &ipa->v4, sizeof(ipa->v4));
1009		if (bits == -1 || bits > 32) {
1010			free(ipa->name);
1011			free(ipa);
1012			return(NULL);
1013		}
1014	} else {
1015		if (inet_pton(AF_INET, s, &ipa->v4) != 1) {
1016			free(ipa->name);
1017			free(ipa);
1018			return (NULL);
1019		}
1020	}
1021
1022	bzero(&ipa->v4mask, sizeof(ipa->v4mask));
1023	if (bits == 32) {
1024		ipa->v4mask.mask32 = 0xffffffff;
1025		ipa->netaddress = 0;
1026	} else {
1027		for (i = 31; i > 31 - bits; i--)
1028			ipa->v4mask.mask32 |= (1 << i);
1029		ipa->v4mask.mask32 = htonl(ipa->v4mask.mask32);
1030		ipa->netaddress = 1;
1031	}
1032
1033	ipa->af = AF_INET;
1034
1035	return (ipa);
1036}
1037
1038struct ipsec_addr *
1039copyhost(const struct ipsec_addr *src)
1040{
1041	struct ipsec_addr *dst;
1042
1043	dst = calloc(1, sizeof(struct ipsec_addr));
1044	if (dst == NULL)
1045		err(1, "copyhost: calloc");
1046
1047	memcpy(dst, src, sizeof(struct ipsec_addr));
1048
1049	if ((dst->name = strdup(src->name)) == NULL)
1050		err(1, "copyhost: strdup");
1051
1052	return dst;
1053}
1054
1055const struct ipsec_xf *
1056parse_xf(const char *name, const struct ipsec_xf xfs[])
1057{
1058	int		i;
1059
1060	for (i = 0; xfs[i].name != NULL; i++) {
1061		if (strncmp(name, xfs[i].name, strlen(name)))
1062			continue;
1063		return &xfs[i];
1064	}
1065	return (NULL);
1066}
1067
1068struct ipsec_transforms *
1069transforms(const char *authname, const char *encname)
1070{
1071	struct ipsec_transforms *xfs;
1072
1073	xfs = calloc(1, sizeof(struct ipsec_transforms));
1074	if (xfs == NULL)
1075		err(1, "transforms: calloc");
1076
1077	if (authname) {
1078		xfs->authxf = parse_xf(authname, authxfs);
1079		if (xfs->authxf == NULL)
1080			yyerror("%s not a valid transform", authname);
1081	}
1082	if (encname) {
1083		xfs->encxf = parse_xf(encname, encxfs);
1084		if (xfs->encxf == NULL)
1085			yyerror("%s not a valid transform", encname);
1086	}
1087
1088	return (xfs);
1089}
1090
1091struct ipsec_transforms *
1092copytransforms(const struct ipsec_transforms *xfs)
1093{
1094	struct ipsec_transforms *newxfs;
1095
1096	if (xfs == NULL)
1097		return (NULL);
1098
1099	newxfs = calloc(1, sizeof(struct ipsec_transforms));
1100	if (newxfs == NULL)
1101		err(1, "copytransforms: calloc");
1102
1103	memcpy(newxfs, xfs, sizeof(struct ipsec_transforms));
1104	return (newxfs);
1105}
1106
1107int
1108validate_sa(u_int32_t spi, u_int8_t protocol, struct ipsec_transforms *xfs,
1109    struct ipsec_key *authkey, struct ipsec_key *enckey)
1110{
1111	/* Sanity checks */
1112	if (spi == 0) {
1113		yyerror("no SPI specified");
1114		return (0);
1115	}
1116	if (protocol == IPSEC_AH) {
1117		if (!xfs) {
1118			yyerror("no transforms specified");
1119			return (0);
1120		}
1121		if (!xfs->authxf)
1122			xfs->authxf = &authxfs[AUTHXF_HMAC_SHA2_256];
1123		if (xfs->encxf) {
1124			yyerror("ah does not provide encryption");
1125			return (0);
1126		}
1127	}
1128	if (protocol == IPSEC_ESP) {
1129		if (!xfs) {
1130			yyerror("no transforms specified");
1131			return (0);
1132		}
1133		if (!xfs->authxf)
1134			xfs->authxf = &authxfs[AUTHXF_HMAC_SHA2_256];
1135		if (!xfs->encxf)
1136			xfs->encxf = &encxfs[ENCXF_AESCTR];
1137	}
1138	if (protocol == IPSEC_TCPMD5 && authkey == NULL) {
1139		yyerror("authentication key needed for tcpmd5");
1140		return (0);
1141	}
1142	if (xfs && xfs->authxf) {
1143		if (!authkey) {
1144			yyerror("no authentication key specified");
1145			return (0);
1146		}
1147		if (authkey->len != xfs->authxf->keymin) {
1148			yyerror("wrong authentication key length, needs to be "
1149			    "%d bits", xfs->authxf->keymin * 8);
1150			return (0);
1151		}
1152	}
1153	if (xfs && xfs->encxf) {
1154		if (!enckey && xfs->encxf != &encxfs[ENCXF_NULL]) {
1155			yyerror("no encryption key specified");
1156			return (0);
1157		}
1158		if (enckey) {
1159		if (enckey->len < xfs->encxf->keymin) {
1160			yyerror("encryption key too short, minimum %d bits",
1161			    xfs->encxf->keymin * 8);
1162			return (0);
1163		}
1164		if (xfs->encxf->keymax < enckey->len) {
1165			yyerror("encryption key too long, maximum %d bits",
1166			    xfs->encxf->keymax * 8);
1167			return (0);
1168		}
1169		}
1170	}
1171
1172	return 1;
1173}
1174
1175struct ipsec_rule *
1176create_sa(u_int8_t protocol, struct ipsec_addr *src, struct ipsec_addr *dst,
1177    u_int32_t spi, struct ipsec_transforms *xfs, struct ipsec_key *authkey,
1178    struct ipsec_key *enckey)
1179{
1180	struct ipsec_rule *r;
1181
1182	if (validate_sa(spi, protocol, xfs, authkey, enckey) == 0)
1183		return (NULL);
1184
1185	r = calloc(1, sizeof(struct ipsec_rule));
1186	if (r == NULL)
1187		err(1, "create_sa: calloc");
1188
1189	r->type |= RULE_SA;
1190	r->proto = protocol;
1191	r->src = src;
1192	r->dst = dst;
1193	r->spi = spi;
1194	r->xfs = xfs;
1195	r->authkey = authkey;
1196	r->enckey = enckey;
1197
1198	return r;
1199}
1200
1201struct ipsec_rule *
1202reverse_sa(struct ipsec_rule *rule, u_int32_t spi, struct ipsec_key *authkey,
1203    struct ipsec_key *enckey)
1204{
1205	struct ipsec_rule *reverse;
1206
1207	if (validate_sa(spi, rule->proto, rule->xfs, authkey, enckey) == 0)
1208		return (NULL);
1209
1210	reverse = calloc(1, sizeof(struct ipsec_rule));
1211	if (reverse == NULL)
1212		err(1, "reverse_sa: calloc");
1213
1214	reverse->type |= RULE_SA;
1215	reverse->proto = rule->proto;
1216	reverse->src = copyhost(rule->dst);
1217	reverse->dst = copyhost(rule->src);
1218	reverse->spi = spi;
1219	reverse->xfs = copytransforms(rule->xfs);
1220	reverse->authkey = authkey;
1221	reverse->enckey = enckey;
1222
1223	return (reverse);
1224}
1225
1226struct ipsec_rule *
1227create_flow(u_int8_t dir, struct ipsec_addr *src, struct ipsec_addr *dst,
1228    struct ipsec_addr *peer, u_int8_t proto, char *srcid, char *dstid,
1229    u_int16_t authtype)
1230{
1231	struct ipsec_rule *r;
1232
1233	r = calloc(1, sizeof(struct ipsec_rule));
1234	if (r == NULL)
1235		err(1, "create_flow: calloc");
1236
1237	r->type |= RULE_FLOW;
1238
1239	if (dir == IPSEC_INOUT)
1240		r->direction = IPSEC_OUT;
1241	else
1242		r->direction = dir;
1243
1244	if (r->direction == IPSEC_IN)
1245		r->flowtype = TYPE_USE;
1246	else
1247		r->flowtype = TYPE_REQUIRE;
1248
1249	r->src = src;
1250	r->dst = dst;
1251
1252	if (peer == NULL) {
1253		/* Set peer to remote host.  Must be a host address. */
1254		if (r->direction == IPSEC_IN) {
1255			if (r->src->netaddress) {
1256				yyerror("no peer specified");
1257				goto errout;
1258			}
1259			r->peer = copyhost(r->src);
1260		} else {
1261			if (r->dst->netaddress) {
1262				yyerror("no peer specified");
1263				goto errout;
1264			}
1265			r->peer = copyhost(r->dst);
1266		}
1267	} else
1268		r->peer = peer;
1269
1270	r->proto = proto;
1271	r->auth = calloc(1, sizeof(struct ipsec_auth));
1272	if (r->auth == NULL)
1273		err(1, "create_flow: calloc");
1274	r->auth->srcid = srcid;
1275	r->auth->dstid = dstid;
1276	r->auth->idtype = ID_FQDN;	/* XXX For now only FQDN. */
1277#ifdef notyet
1278	r->auth->type = authtype;
1279#endif
1280
1281	return r;
1282
1283errout:
1284	free(r);
1285	if (srcid)
1286		free(srcid);
1287	if (dstid)
1288		free(dstid);
1289	free(src);
1290	free(dst);
1291
1292	return NULL;
1293}
1294
1295struct ipsec_rule *
1296reverse_rule(struct ipsec_rule *rule)
1297{
1298	struct ipsec_rule *reverse;
1299
1300	reverse = calloc(1, sizeof(struct ipsec_rule));
1301	if (reverse == NULL)
1302		err(1, "reverse_rule: calloc");
1303
1304	reverse->type |= RULE_FLOW;
1305
1306	if (rule->direction == (u_int8_t)IPSEC_OUT) {
1307		reverse->direction = (u_int8_t)IPSEC_IN;
1308		reverse->flowtype = TYPE_USE;
1309	} else {
1310		reverse->direction = (u_int8_t)IPSEC_OUT;
1311		reverse->flowtype = TYPE_REQUIRE;
1312	}
1313
1314	reverse->src = copyhost(rule->dst);
1315	reverse->dst = copyhost(rule->src);
1316	reverse->peer = copyhost(rule->peer);
1317	reverse->proto = (u_int8_t)rule->proto;
1318
1319	reverse->auth = calloc(1, sizeof(struct ipsec_auth));
1320	if (reverse->auth == NULL)
1321		err(1, "reverse_rule: calloc");
1322	if (rule->auth->dstid && (reverse->auth->dstid =
1323	    strdup(rule->auth->dstid)) == NULL)
1324		err(1, "reverse_rule: strdup");
1325	if (rule->auth->srcid && (reverse->auth->srcid =
1326	    strdup(rule->auth->srcid)) == NULL)
1327		err(1, "reverse_rule: strdup");
1328	reverse->auth->idtype = rule->auth->idtype;
1329	reverse->auth->type = rule->auth->type;
1330
1331	return reverse;
1332}
1333
1334struct ipsec_rule *
1335create_ike(struct ipsec_addr *src, struct ipsec_addr *dst, struct ipsec_addr *
1336    peer, struct ipsec_transforms *mmxfs, struct ipsec_transforms *qmxfs,
1337    u_int8_t proto, u_int8_t mode, char *srcid, char *dstid)
1338{
1339	struct ipsec_rule *r;
1340
1341	r = calloc(1, sizeof(struct ipsec_rule));
1342	if (r == NULL)
1343		err(1, "create_ike: calloc");
1344
1345	r->type = RULE_IKE;
1346
1347	r->src = src;
1348	r->dst = dst;
1349
1350	if (peer == NULL) {
1351		/* Set peer to remote host.  Must be a host address. */
1352		if (r->direction == IPSEC_IN) {
1353			if (r->src->netaddress) {
1354				yyerror("no peer specified");
1355				goto errout;
1356			}
1357			r->peer = copyhost(r->src);
1358		} else {
1359			if (r->dst->netaddress) {
1360				yyerror("no peer specified");
1361				goto errout;
1362			}
1363			r->peer = copyhost(r->dst);
1364		}
1365	} else
1366		r->peer = peer;
1367
1368	r->proto = proto;
1369	r->ikemode = mode;
1370	r->mmxfs = mmxfs;
1371	r->qmxfs = qmxfs;
1372	r->auth = calloc(1, sizeof(struct ipsec_auth));
1373	if (r->auth == NULL)
1374		err(1, "create_ike: calloc");
1375	r->auth->srcid = srcid;
1376	r->auth->dstid = dstid;
1377	r->auth->idtype = ID_FQDN;	/* XXX For now only FQDN. */
1378
1379	return (r);
1380
1381errout:
1382	free(r);
1383	if (srcid)
1384		free(srcid);
1385	if (dstid)
1386		free(dstid);
1387	free(src);
1388	free(dst);
1389
1390	return (NULL);
1391}
1392