parse.y revision 1.23
1/*	$OpenBSD: parse.y,v 1.23 2005/08/19 08:47:56 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 *);
125
126typedef struct {
127	union {
128		u_int32_t	 number;
129		u_int8_t	 dir;
130		char		*string;
131		int		 log;
132		u_int8_t	 protocol;
133		struct {
134			struct ipsec_addr *src;
135			struct ipsec_addr *dst;
136		} hosts;
137		struct ipsec_addr *peer;
138		struct ipsec_addr *host;
139		struct {
140			char *srcid;
141			char *dstid;
142		} ids;
143		char		*id;
144		u_int16_t	 authtype;
145		struct {
146			u_int32_t	spiout;
147			u_int32_t	spiin;
148		} spis;
149		struct {
150			struct ipsec_key *keyout;
151			struct ipsec_key *keyin;
152		} authkeys;
153		struct {
154			struct ipsec_key *keyout;
155			struct ipsec_key *keyin;
156		} enckeys;
157		struct {
158			struct ipsec_key *keyout;
159			struct ipsec_key *keyin;
160		} keys;
161		struct ipsec_transforms *transforms;
162	} v;
163	int lineno;
164} YYSTYPE;
165
166%}
167
168%token	FLOW FROM ESP AH IN PEER ON OUT TO SRCID DSTID RSA PSK TCPMD5 SPI
169%token	AUTHKEY ENCKEY FILENAME AUTHXF ENCXF ERROR
170%token	<v.string>		STRING
171%type	<v.dir>			dir
172%type	<v.protocol>		protocol
173%type	<v.number>		number
174%type	<v.hosts>		hosts
175%type	<v.peer>		peer
176%type	<v.host>		host
177%type	<v.ids>			ids
178%type	<v.id>			id
179%type	<v.authtype>		authtype
180%type	<v.spis>		spispec
181%type	<v.authkeys>		authkeyspec
182%type	<v.enckeys>		enckeyspec
183%type	<v.keys>		keyspec
184%type	<v.transforms>		transforms
185%%
186
187grammar		: /* empty */
188		| grammar '\n'
189		| grammar flowrule '\n'
190		| grammar sarule '\n'
191		| grammar tcpmd5rule '\n'
192		| grammar error '\n'		{ errors++; }
193		;
194
195number		: STRING			{
196			unsigned long	ulval;
197
198			if (atoul($1, &ulval) == -1) {
199				yyerror("%s is not a number", $1);
200				free($1);
201				YYERROR;
202			}
203			if (ulval > UINT_MAX) {
204				yyerror("0x%lx out of range", ulval);
205				free($1);
206				YYERROR;
207			}
208			$$ = (u_int32_t)ulval;
209			free($1);
210		}
211
212tcpmd5rule	: TCPMD5 hosts spispec authkeyspec	{
213			struct ipsec_rule	*r;
214
215			r = create_sa(IPSEC_TCPMD5, $2.src, $2.dst, $3.spiout,
216			    NULL, $4.keyout, NULL);
217			if (r == NULL)
218				YYERROR;
219			r->nr = ipsec->rule_nr++;
220
221			if (ipsecctl_add_rule(ipsec, r))
222				errx(1, "tcpmd5rule: ipsecctl_add_rule");
223
224			/* Create and add reverse SA rule. */
225			if ($3.spiin != 0 || $4.keyin != NULL) {
226				r = reverse_sa(r, $3.spiin, $4.keyin, NULL);
227				if (r == NULL)
228					YYERROR;
229				r->nr = ipsec->rule_nr++;
230
231				if (ipsecctl_add_rule(ipsec, r))
232					errx(1, "tcpmd5rule: ipsecctl_add_rule");
233			}
234		}
235		;
236
237sarule		: protocol hosts spispec transforms authkeyspec enckeyspec {
238			struct ipsec_rule	*r;
239
240			r = create_sa($1, $2.src, $2.dst, $3.spiout, $4,
241			    $5.keyout, $6.keyout);
242			if (r == NULL)
243				YYERROR;
244			r->nr = ipsec->rule_nr++;
245
246			if (ipsecctl_add_rule(ipsec, r))
247				errx(1, "sarule: ipsecctl_add_rule");
248
249			/* Create and add reverse SA rule. */
250			if ($3.spiin != 0 || $5.keyin || $6.keyin) {
251				r = reverse_sa(r, $3.spiin, $5.keyin,
252				    $6.keyin);
253				if (r == NULL)
254					YYERROR;
255				r->nr = ipsec->rule_nr++;
256
257				if (ipsecctl_add_rule(ipsec, r))
258					errx(1, "sarule: ipsecctl_add_rule");
259			}
260		}
261		;
262
263flowrule	: FLOW protocol dir hosts peer ids authtype	{
264			struct ipsec_rule	*r;
265
266			r = create_flow($3, $4.src, $4.dst, $5, $2, $6.srcid,
267			    $6.dstid, $7);
268			if (r == NULL)
269				YYERROR;
270			r->nr = ipsec->rule_nr++;
271
272			if (ipsecctl_add_rule(ipsec, r))
273				errx(1, "flowrule: ipsecctl_add_rule");
274
275			/* Create and add reverse flow rule. */
276			if ($3 == IPSEC_INOUT) {
277				r = reverse_rule(r);
278				r->nr = ipsec->rule_nr++;
279
280				if (ipsecctl_add_rule(ipsec, r))
281					errx(1, "flowrule: ipsecctl_add_rule");
282			}
283		}
284		;
285
286protocol	: /* empty */			{ $$ = IPSEC_ESP; }
287		| ESP				{ $$ = IPSEC_ESP; }
288		| AH				{ $$ = IPSEC_AH; }
289		;
290
291dir		: /* empty */			{ $$ = IPSEC_INOUT; }
292		| IN				{ $$ = IPSEC_IN; }
293		| OUT				{ $$ = IPSEC_OUT; }
294		;
295
296hosts		: FROM host TO host		{
297			$$.src = $2;
298			$$.dst = $4;
299		}
300		;
301
302peer		: /* empty */			{ $$ = NULL; }
303		| PEER STRING			{
304			if (($$ = host($2)) == NULL) {
305				free($2);
306				yyerror("could not parse host specification");
307				YYERROR;
308			}
309			free($2);
310		}
311		;
312
313host		: STRING			{
314			if (($$ = host($1)) == NULL) {
315				free($1);
316				yyerror("could not parse host specification");
317				YYERROR;
318			}
319			free($1);
320		}
321		| STRING '/' number		{
322			char	*buf;
323
324			if (asprintf(&buf, "%s/%u", $1, $3) == -1)
325				err(1, "host: asprintf");
326			free($1);
327			if (($$ = host(buf)) == NULL)	{
328				free(buf);
329				yyerror("could not parse host specification");
330				YYERROR;
331			}
332			free(buf);
333		}
334		;
335
336ids		: /* empty */			{
337			$$.srcid = NULL;
338			$$.dstid = NULL;
339		}
340		| SRCID id DSTID id		{
341			$$.srcid = $2;
342			$$.dstid = $4;
343		}
344		| SRCID id			{
345			$$.srcid = $2;
346			$$.dstid = NULL;
347		}
348		| DSTID id			{
349			$$.srcid = NULL;
350			$$.dstid = $2;
351		}
352		;
353
354id		: STRING			{ $$ = $1; }
355		;
356
357authtype	: /* empty */			{ $$ = 0; }
358		| RSA				{ $$ = AUTH_RSA; }
359		| PSK				{ $$ = AUTH_PSK; }
360		;
361
362spispec		: SPI STRING			{
363			u_int32_t	 spi;
364			char		*p = strchr($2, ':');
365
366			if (p != NULL) {
367				*p++ = 0;
368
369				if (atospi(p, &spi) == -1) {
370					yyerror("%s is not a valid spi", p);
371					free($2);
372					YYERROR;
373				}
374				$$.spiin = spi;
375			}
376			if (atospi($2, &spi) == -1) {
377				yyerror("%s is not a valid spi", $2);
378				free($2);
379				YYERROR;
380			}
381			$$.spiout = spi;
382
383
384			free($2);
385		}
386		;
387
388transforms	: /* empty */			{
389			struct ipsec_transforms *xfs;
390
391			if ((xfs = calloc(1, sizeof(struct ipsec_transforms)))
392			    == NULL)
393				err(1, "calloc");
394			$$ = xfs;
395		}
396		| AUTHXF STRING ENCXF STRING	{
397			if (($$ = transforms($2, $4)) == NULL) {
398				free($2);
399				free($4);
400				yyerror("could not parse transforms");
401				YYERROR;
402			}
403			free($2);
404			free($4);
405		}
406		| AUTHXF STRING			{
407			if (($$ = transforms($2, NULL)) == NULL) {
408				free($2);
409				yyerror("could not parse transforms");
410				YYERROR;
411			}
412			free($2);
413		}
414		| ENCXF STRING			{
415			if (($$ = transforms(NULL, $2)) == NULL) {
416				free($2);
417				yyerror("could not parse transforms");
418				YYERROR;
419			}
420			free($2);
421		}
422		;
423
424authkeyspec	: /* empty */			{
425			$$.keyout = NULL;
426			$$.keyin = NULL;
427		}
428		| AUTHKEY keyspec		{
429			$$.keyout = $2.keyout;
430			$$.keyin = $2.keyin;
431		}
432		;
433
434enckeyspec	: /* empty */			{
435			$$.keyout = NULL;
436			$$.keyin = NULL;
437		}
438		| ENCKEY keyspec		{
439			$$.keyout = $2.keyout;
440			$$.keyin = $2.keyin;
441		}
442		;
443
444keyspec		: STRING			{
445			unsigned char	*hex;
446			unsigned char	*p = strchr($1, ':');
447
448			if (p != NULL ) {
449				*p++ = 0;
450
451				if (!strncmp(p, "0x", 2))
452					p += 2;
453				$$.keyin = parsekey(p, strlen(p));
454			}
455
456			hex = $1;
457			if (!strncmp(hex, "0x", 2))
458				hex += 2;
459			$$.keyout = parsekey(hex, strlen(hex));
460
461			free($1);
462		}
463		| FILENAME STRING		{
464			unsigned char	*p = strchr($2, ':');
465
466			if (p != NULL) {
467				*p++ = 0;
468				$$.keyin = parsekeyfile(p);
469			}
470			$$.keyout = parsekeyfile($2);
471			free($2);
472		}
473		;
474%%
475
476struct keywords {
477	const char	*k_name;
478	int		 k_val;
479};
480
481int
482yyerror(const char *fmt, ...)
483{
484	va_list		 ap;
485	extern char 	*infile;
486
487	errors = 1;
488	va_start(ap, fmt);
489	fprintf(stderr, "%s: %d: ", infile, yyval.lineno);
490	vfprintf(stderr, fmt, ap);
491	fprintf(stderr, "\n");
492	va_end(ap);
493	return (0);
494}
495
496int
497kw_cmp(const void *k, const void *e)
498{
499	return (strcmp(k, ((const struct keywords *)e)->k_name));
500}
501
502int
503lookup(char *s)
504{
505	/* this has to be sorted always */
506	static const struct keywords keywords[] = {
507		{ "ah",			AH},
508		{ "auth",		AUTHXF},
509		{ "authkey",		AUTHKEY},
510		{ "dstid",		DSTID},
511		{ "enc",		ENCXF},
512		{ "enckey",		ENCKEY},
513		{ "esp",		ESP},
514		{ "file",		FILENAME},
515		{ "flow",		FLOW},
516		{ "from",		FROM},
517		{ "in",			IN},
518		{ "out",		OUT},
519		{ "peer",		PEER},
520		{ "psk",		PSK},
521		{ "rsa",		RSA},
522		{ "spi",		SPI},
523		{ "srcid",		SRCID},
524		{ "tcpmd5",		TCPMD5},
525		{ "to",			TO},
526	};
527	const struct keywords	*p;
528
529	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
530	    sizeof(keywords[0]), kw_cmp);
531
532	if (p) {
533		if (debug > 1)
534			fprintf(stderr, "%s: %d\n", s, p->k_val);
535		return (p->k_val);
536	} else {
537		if (debug > 1)
538			fprintf(stderr, "string: %s\n", s);
539		return (STRING);
540	}
541}
542
543#define MAXPUSHBACK	128
544
545char	*parsebuf;
546int	 parseindex;
547char	 pushback_buffer[MAXPUSHBACK];
548int	 pushback_index = 0;
549
550int
551lgetc(FILE *f)
552{
553	int	c, next;
554
555	if (parsebuf) {
556		/* Read character from the parsebuffer instead of input. */
557		if (parseindex >= 0) {
558			c = parsebuf[parseindex++];
559			if (c != '\0')
560				return (c);
561			parsebuf = NULL;
562		} else
563			parseindex++;
564	}
565
566	if (pushback_index)
567		return (pushback_buffer[--pushback_index]);
568
569	while ((c = getc(f)) == '\\') {
570		next = getc(f);
571		if (next != '\n') {
572			if (isspace(next))
573				yyerror("whitespace after \\");
574			ungetc(next, f);
575			break;
576		}
577		yylval.lineno = lineno;
578		lineno++;
579	}
580	if (c == '\t' || c == ' ') {
581		/* Compress blanks to a single space. */
582		do {
583			c = getc(f);
584		} while (c == '\t' || c == ' ');
585		ungetc(c, f);
586		c = ' ';
587	}
588
589	return (c);
590}
591
592int
593lungetc(int c)
594{
595	if (c == EOF)
596		return (EOF);
597	if (parsebuf) {
598		parseindex--;
599		if (parseindex >= 0)
600			return (c);
601	}
602	if (pushback_index < MAXPUSHBACK-1)
603		return (pushback_buffer[pushback_index++] = c);
604	else
605		return (EOF);
606}
607
608int
609findeol(void)
610{
611	int	c;
612
613	parsebuf = NULL;
614	pushback_index = 0;
615
616	/* skip to either EOF or the first real EOL */
617	while (1) {
618		c = lgetc(fin);
619		if (c == '\n') {
620			lineno++;
621			break;
622		}
623		if (c == EOF)
624			break;
625	}
626	return (ERROR);
627}
628
629int
630yylex(void)
631{
632	char	 buf[8096];
633	char	*p, *val;
634	int	 endc, c;
635	int	 token;
636
637top:
638	p = buf;
639	while ((c = lgetc(fin)) == ' ')
640		; /* nothing */
641
642	yylval.lineno = lineno;
643	if (c == '#')
644		while ((c = lgetc(fin)) != '\n' && c != EOF)
645			; /* nothing */
646	if (c == '$' && parsebuf == NULL) {
647		while (1) {
648			if ((c = lgetc(fin)) == EOF)
649				return (0);
650
651			if (p + 1 >= buf + sizeof(buf) - 1) {
652				yyerror("string too long");
653				return (findeol());
654			}
655			if (isalnum(c) || c == '_') {
656				*p++ = (char)c;
657				continue;
658			}
659			*p = '\0';
660			lungetc(c);
661			break;
662		}
663		val = symget(buf);
664		if (val == NULL) {
665			yyerror("macro \"%s\" not defined", buf);
666			return (findeol());
667		}
668		parsebuf = val;
669		parseindex = 0;
670		goto top;
671	}
672
673	switch (c) {
674	case '\'':
675	case '"':
676		endc = c;
677		while (1) {
678			if ((c = lgetc(fin)) == EOF)
679				return (0);
680			if (c == endc) {
681				*p = '\0';
682				break;
683			}
684			if (c == '\n') {
685				lineno++;
686				continue;
687			}
688			if (p + 1 >= buf + sizeof(buf) - 1) {
689				yyerror("string too long");
690				return (findeol());
691			}
692			*p++ = (char)c;
693		}
694		yylval.v.string = strdup(buf);
695		if (yylval.v.string == NULL)
696			err(1, "yylex: strdup");
697		return (STRING);
698	}
699
700#define allowed_in_string(x) \
701	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
702	x != '{' && x != '}' && x != '<' && x != '>' && \
703	x != '!' && x != '=' && x != '/' && x != '#' && \
704	x != ','))
705
706	if (isalnum(c) || c == ':' || c == '_' || c == '*') {
707		do {
708			*p++ = c;
709			if ((unsigned)(p-buf) >= sizeof(buf)) {
710				yyerror("string too long");
711				return (findeol());
712			}
713		} while ((c = lgetc(fin)) != EOF && (allowed_in_string(c)));
714		lungetc(c);
715		*p = '\0';
716		if ((token = lookup(buf)) == STRING)
717			if ((yylval.v.string = strdup(buf)) == NULL)
718				err(1, "yylex: strdup");
719		return (token);
720	}
721	if (c == '\n') {
722		yylval.lineno = lineno;
723		lineno++;
724	}
725	if (c == EOF)
726		return (0);
727	return (c);
728}
729
730int
731parse_rules(FILE *input, struct ipsecctl *ipsecx)
732{
733	struct sym	*sym, *next;
734
735	ipsec = ipsecx;
736	fin = input;
737	lineno = 1;
738	errors = 0;
739
740	yyparse();
741
742	/* Free macros and check which have not been used. */
743	for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
744		next = TAILQ_NEXT(sym, entries);
745		free(sym->nam);
746		free(sym->val);
747		TAILQ_REMOVE(&symhead, sym, entries);
748		free(sym);
749	}
750
751	return (errors ? -1 : 0);
752}
753
754int
755symset(const char *nam, const char *val, int persist)
756{
757	struct sym	*sym;
758
759	for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
760	    sym = TAILQ_NEXT(sym, entries))
761		;	/* nothing */
762
763	if (sym != NULL) {
764		if (sym->persist == 1)
765			return (0);
766		else {
767			free(sym->nam);
768			free(sym->val);
769			TAILQ_REMOVE(&symhead, sym, entries);
770			free(sym);
771		}
772	}
773	if ((sym = calloc(1, sizeof(*sym))) == NULL)
774		return (-1);
775
776	sym->nam = strdup(nam);
777	if (sym->nam == NULL) {
778		free(sym);
779		return (-1);
780	}
781	sym->val = strdup(val);
782	if (sym->val == NULL) {
783		free(sym->nam);
784		free(sym);
785		return (-1);
786	}
787	sym->used = 0;
788	sym->persist = persist;
789	TAILQ_INSERT_TAIL(&symhead, sym, entries);
790	return (0);
791}
792
793int
794cmdline_symset(char *s)
795{
796	char	*sym, *val;
797	int	ret;
798	size_t	len;
799
800	if ((val = strrchr(s, '=')) == NULL)
801		return (-1);
802
803	len = strlen(s) - strlen(val) + 1;
804	if ((sym = malloc(len)) == NULL)
805		err(1, "cmdline_symset: malloc");
806
807	strlcpy(sym, s, len);
808
809	ret = symset(sym, val + 1, 1);
810	free(sym);
811
812	return (ret);
813}
814
815char *
816symget(const char *nam)
817{
818	struct sym	*sym;
819
820	TAILQ_FOREACH(sym, &symhead, entries)
821		if (strcmp(nam, sym->nam) == 0) {
822			sym->used = 1;
823			return (sym->val);
824		}
825	return (NULL);
826}
827
828int
829atoul(char *s, u_long *ulvalp)
830{
831	u_long	 ulval;
832	char	*ep;
833
834	errno = 0;
835	ulval = strtoul(s, &ep, 0);
836	if (s[0] == '\0' || *ep != '\0')
837		return (-1);
838	if (errno == ERANGE && ulval == ULONG_MAX)
839		return (-1);
840	*ulvalp = ulval;
841	return (0);
842}
843
844int
845atospi(char *s, u_int32_t *spivalp)
846{
847	unsigned long	ulval;
848
849	if (atoul(s, &ulval) == -1)
850		return (-1);
851	if (ulval >= SPI_RESERVED_MIN && ulval <= SPI_RESERVED_MAX) {
852		yyerror("illegal SPI value");
853		return (-1);
854	}
855	*spivalp = ulval;
856	return (0);
857}
858
859u_int8_t
860x2i(unsigned char *s)
861{
862	char	ss[3];
863
864	ss[0] = s[0];
865	ss[1] = s[1];
866	ss[2] = 0;
867
868	if (!isxdigit(s[0]) || !isxdigit(s[1])) {
869		yyerror("keys need to be specified in hex digits");
870		return (-1);
871	}
872	return ((u_int8_t)strtoul(ss, NULL, 16));
873}
874
875struct ipsec_key *
876parsekey(unsigned char *hexkey, size_t len)
877{
878	struct ipsec_key *key;
879	int		  i;
880
881	key = calloc(1, sizeof(struct ipsec_key));
882	if (key == NULL)
883		err(1, "calloc");
884
885	key->len = len / 2;
886	key->data = calloc(key->len, sizeof(u_int8_t));
887	if (key->data == NULL)
888		err(1, "calloc");
889
890	for (i = 0; i < (int)key->len; i++)
891		key->data[i] = x2i(hexkey + 2 * i);
892
893	return (key);
894}
895
896struct ipsec_key *
897parsekeyfile(char *filename)
898{
899	struct stat	 sb;
900	int		 fd;
901	unsigned char	*hex;
902
903	if (stat(filename, &sb) < 0)
904		err(1, "stat %s", filename);
905	if ((sb.st_size > KEYSIZE_LIMIT) || (sb.st_size == 0))
906		errx(1, "key too %s", sb.st_size ? "large" :
907		    "small");
908	if ((hex = calloc(sb.st_size, sizeof(unsigned char)))
909	    == NULL)
910		err(1, "calloc");
911	if ((fd = open(filename, O_RDONLY)) < 0)
912		err(1, "open");
913	if (read(fd, hex, sb.st_size) < sb.st_size)
914		err(1, "read");
915	close(fd);
916	return (parsekey(hex, sb.st_size));
917}
918
919struct ipsec_addr *
920host(const char *s)
921{
922	struct ipsec_addr	*ipa;
923	int			 i, bits = 32;
924
925	/* XXX for now only AF_INET. */
926
927	ipa = calloc(1, sizeof(struct ipsec_addr));
928	if (ipa == NULL)
929		err(1, "calloc");
930
931	if (strrchr(s, '/') != NULL) {
932		bits = inet_net_pton(AF_INET, s, &ipa->v4, sizeof(ipa->v4));
933		if (bits == -1 || bits > 32) {
934			free(ipa);
935			return(NULL);
936		}
937	} else {
938		if (inet_pton(AF_INET, s, &ipa->v4) != 1) {
939			free(ipa);
940			return NULL;
941		}
942	}
943
944	bzero(&ipa->v4mask, sizeof(ipa->v4mask));
945	if (bits == 32) {
946		ipa->v4mask.mask32 = 0xffffffff;
947		ipa->netaddress = 0;
948	} else {
949		for (i = 31; i > 31 - bits; i--)
950			ipa->v4mask.mask32 |= (1 << i);
951		ipa->v4mask.mask32 = htonl(ipa->v4mask.mask32);
952		ipa->netaddress = 1;
953	}
954
955	ipa->af = AF_INET;
956
957	return ipa;
958}
959
960struct ipsec_addr *
961copyhost(const struct ipsec_addr *src)
962{
963	struct ipsec_addr *dst;
964
965	dst = calloc(1, sizeof(struct ipsec_addr));
966	if (dst == NULL)
967		err(1, "calloc");
968
969	memcpy(dst, src, sizeof(struct ipsec_addr));
970	return dst;
971}
972
973const struct ipsec_xf *
974parse_xf(const char *name, const struct ipsec_xf xfs[])
975{
976	int		i;
977
978	for (i = 0; xfs[i].name != NULL; i++) {
979		if (strncmp(name, xfs[i].name, strlen(name)))
980			continue;
981		return &xfs[i];
982	}
983	return (NULL);
984}
985
986struct ipsec_transforms *
987transforms(const char *authname, const char *encname)
988{
989	struct ipsec_transforms *xfs;
990
991	xfs = calloc(1, sizeof(struct ipsec_transforms));
992	if (xfs == NULL)
993		err(1, "calloc");
994
995	if (authname)
996		xfs->authxf = parse_xf(authname, authxfs);
997	if (encname)
998		xfs->encxf = parse_xf(encname, encxfs);
999
1000	return (xfs);
1001}
1002
1003struct ipsec_transforms *
1004copytransforms(const struct ipsec_transforms *xfs)
1005{
1006	struct ipsec_transforms *newxfs;
1007
1008	if (xfs == NULL)
1009		return (NULL);
1010
1011	newxfs = calloc(1, sizeof(struct ipsec_transforms));
1012	if (newxfs == NULL)
1013		err(1, "calloc");
1014
1015	memcpy(newxfs, xfs, sizeof(struct ipsec_transforms));
1016	return (newxfs);
1017}
1018
1019int
1020validate_sa(u_int32_t spi, u_int8_t protocol, struct ipsec_transforms *xfs,
1021    struct ipsec_key *authkey, struct ipsec_key *enckey)
1022{
1023	/* Sanity checks */
1024	if (spi == 0) {
1025		yyerror("no SPI specified");
1026		return (0);
1027	}
1028	if (protocol == IPSEC_AH) {
1029		if (!xfs) {
1030			yyerror("no transforms specified");
1031			return (0);
1032		}
1033		if (!xfs->authxf)
1034			xfs->authxf = &authxfs[AUTHXF_HMAC_SHA2_256];
1035		if (xfs->encxf) {
1036			yyerror("ah does not provide encryption");
1037			return (0);
1038		}
1039	}
1040	if (protocol == IPSEC_ESP) {
1041		if (!xfs) {
1042			yyerror("no transforms specified");
1043			return (0);
1044		}
1045		if (!xfs->authxf)
1046			xfs->authxf = &authxfs[AUTHXF_HMAC_SHA2_256];
1047		if (!xfs->encxf)
1048			xfs->encxf = &encxfs[ENCXF_AESCTR];
1049	}
1050	if (protocol == IPSEC_TCPMD5 && authkey == NULL) {
1051		yyerror("authentication key needed for tcpmd5");
1052		return (0);
1053	}
1054	if (xfs && xfs->authxf) {
1055		if (!authkey) {
1056			yyerror("no authentication key specified");
1057			return (0);
1058		}
1059		if (authkey->len != xfs->authxf->keymin) {
1060			yyerror("wrong authentication key length, needs to be "
1061			    "%d bits", xfs->authxf->keymin * 8);
1062			return (0);
1063		}
1064	}
1065	if (xfs && xfs->encxf) {
1066		if (!enckey && xfs->encxf != &encxfs[ENCXF_NULL]) {
1067			yyerror("no encryption key specified");
1068			return (0);
1069		}
1070		if (enckey) {
1071		if (enckey->len < xfs->encxf->keymin) {
1072			yyerror("encryption key too short, minimum %d bits",
1073			    xfs->encxf->keymin * 8);
1074			return (0);
1075		}
1076		if (xfs->encxf->keymax < enckey->len) {
1077			yyerror("encryption key too long, maximum %d bits",
1078			    xfs->encxf->keymax * 8);
1079			return (0);
1080		}
1081		}
1082	}
1083
1084	return 1;
1085}
1086
1087struct ipsec_rule *
1088create_sa(u_int8_t protocol, struct ipsec_addr *src, struct ipsec_addr *dst,
1089    u_int32_t spi, struct ipsec_transforms *xfs, struct ipsec_key *authkey,
1090    struct ipsec_key *enckey)
1091{
1092	struct ipsec_rule *r;
1093
1094	if (validate_sa(spi, protocol, xfs, authkey, enckey) == 0)
1095		return (NULL);
1096
1097	r = calloc(1, sizeof(struct ipsec_rule));
1098	if (r == NULL)
1099		err(1, "calloc");
1100
1101	r->type |= RULE_SA;
1102	r->proto = protocol;
1103	r->src = src;
1104	r->dst = dst;
1105	r->spi = spi;
1106	r->xfs = xfs;
1107	r->authkey = authkey;
1108	r->enckey = enckey;
1109
1110	return r;
1111}
1112
1113struct ipsec_rule *
1114reverse_sa(struct ipsec_rule *rule, u_int32_t spi, struct ipsec_key *authkey,
1115    struct ipsec_key *enckey)
1116{
1117	struct ipsec_rule *reverse;
1118
1119	if (validate_sa(spi, rule->proto, rule->xfs, authkey, enckey) == 0)
1120		return (NULL);
1121
1122	reverse = calloc(1, sizeof(struct ipsec_rule));
1123	if (reverse == NULL)
1124		err(1, "calloc");
1125
1126	reverse->type |= RULE_SA;
1127	reverse->proto = rule->proto;
1128	reverse->src = copyhost(rule->dst);
1129	reverse->dst = copyhost(rule->src);
1130	reverse->spi = spi;
1131	reverse->xfs = copytransforms(rule->xfs);
1132	reverse->authkey = authkey;
1133	reverse->enckey = enckey;
1134
1135	return (reverse);
1136}
1137
1138struct ipsec_rule *
1139create_flow(u_int8_t dir, struct ipsec_addr *src, struct ipsec_addr *dst,
1140    struct ipsec_addr *peer, u_int8_t proto, char *srcid, char *dstid,
1141    u_int16_t authtype)
1142{
1143	struct ipsec_rule *r;
1144
1145	r = calloc(1, sizeof(struct ipsec_rule));
1146	if (r == NULL)
1147		err(1, "calloc");
1148
1149	r->type |= RULE_FLOW;
1150
1151	if (dir == IPSEC_INOUT)
1152		r->direction = IPSEC_OUT;
1153	else
1154		r->direction = dir;
1155
1156	if (r->direction == IPSEC_IN)
1157		r->flowtype = TYPE_USE;
1158	else
1159		r->flowtype = TYPE_REQUIRE;
1160
1161	r->src = src;
1162	r->dst = dst;
1163
1164	if (peer == NULL) {
1165		/* Set peer to remote host.  Must be a host address. */
1166		if (r->direction == IPSEC_IN) {
1167			if (r->src->netaddress) {
1168				yyerror("no peer specified");
1169				goto errout;
1170			}
1171			r->peer = copyhost(r->src);
1172		} else {
1173			if (r->dst->netaddress) {
1174				yyerror("no peer specified");
1175				goto errout;
1176			}
1177			r->peer = copyhost(r->dst);
1178		}
1179	} else
1180		r->peer = peer;
1181
1182	r->proto = proto;
1183	r->auth = calloc(1, sizeof(struct ipsec_auth));
1184	if (r->auth == NULL)
1185		err(1, "calloc");
1186	r->auth->srcid = srcid;
1187	r->auth->dstid = dstid;
1188	r->auth->idtype = ID_FQDN;	/* XXX For now only FQDN. */
1189#ifdef notyet
1190	r->auth->type = authtype;
1191#endif
1192
1193	return r;
1194
1195errout:
1196	free(r);
1197	if (srcid)
1198		free(srcid);
1199	if (dstid)
1200		free(dstid);
1201	free(src);
1202	free(dst);
1203
1204	return NULL;
1205}
1206
1207struct ipsec_rule *
1208reverse_rule(struct ipsec_rule *rule)
1209{
1210	struct ipsec_rule *reverse;
1211
1212	reverse = calloc(1, sizeof(struct ipsec_rule));
1213	if (reverse == NULL)
1214		err(1, "calloc");
1215
1216	reverse->type |= RULE_FLOW;
1217
1218	if (rule->direction == (u_int8_t)IPSEC_OUT) {
1219		reverse->direction = (u_int8_t)IPSEC_IN;
1220		reverse->flowtype = TYPE_USE;
1221	} else {
1222		reverse->direction = (u_int8_t)IPSEC_OUT;
1223		reverse->flowtype = TYPE_REQUIRE;
1224	}
1225
1226	reverse->src = copyhost(rule->dst);
1227	reverse->dst = copyhost(rule->src);
1228	reverse->peer = copyhost(rule->peer);
1229	reverse->proto = (u_int8_t)rule->proto;
1230
1231	reverse->auth = calloc(1, sizeof(struct ipsec_auth));
1232	if (reverse->auth == NULL)
1233		err(1, "calloc");
1234	if (rule->auth->dstid && (reverse->auth->dstid =
1235	    strdup(rule->auth->dstid)) == NULL)
1236		err(1, "strdup");
1237	if (rule->auth->srcid && (reverse->auth->srcid =
1238	    strdup(rule->auth->srcid)) == NULL)
1239		err(1, "strdup");
1240	reverse->auth->idtype = rule->auth->idtype;
1241	reverse->auth->type = rule->auth->type;
1242
1243	return reverse;
1244}
1245