veriexecctl_parse.y revision 1.10
1%{
2/*	$NetBSD: veriexecctl_parse.y,v 1.10 2005/06/13 15:18:44 elad Exp $	*/
3
4/*-
5 * Copyright 2005 Elad Efrat <elad@bsd.org.il>
6 * Copyright 2005 Brett Lymn <blymn@netbsd.org>
7 *
8 * All rights reserved.
9 *
10 * This code has been donated to The NetBSD Foundation by the Author.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. The name of the author may not be used to endorse or promote products
18 *    derived from this software withough specific prior written permission
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 *
32 */
33
34#include <sys/param.h>
35#include <sys/ioctl.h>
36#include <sys/statvfs.h>
37#include <sys/mount.h>
38
39#include <sys/verified_exec.h>
40#include <ctype.h>
41#include <stdio.h>
42#include <string.h>
43#include <errno.h>
44#include <err.h>
45
46#include "veriexecctl.h"
47
48struct veriexec_params params;
49static int convert(u_char *, u_char *);
50
51int have_type = 0;
52
53#define	FIELD_TYPE	1
54%}
55
56%union {
57	char *string;
58	int intval;
59}
60
61%token <string> PATH
62%token <string> STRING
63%token EOL TOKEN_COMMA
64
65%%
66
67statement	:	/* empty */
68		|	statement path type fingerprint flags eol {
69	struct stat sb;
70	struct veriexec_up *p;
71
72	if (phase == 2) {
73		phase2_load();
74		goto phase_2_end;
75	}
76
77	if (stat(params.file, &sb) == -1) {
78		warnx("Line %lu: Can't stat `%s'",
79		    (unsigned long)line, params.file);
80		goto phase_2_end;
81	}
82
83	/* Only regular files */
84	if (!S_ISREG(sb.st_mode)) {
85		warnx("Line %lu: %s is not a regular file",
86		    (unsigned long)line, params.file);
87		goto phase_2_end;
88	}
89
90	if ((p = dev_lookup(sb.st_dev)) != NULL) {
91	    (p->vu_param.hash_size)++;
92	    goto phase_2_end;
93	}
94
95	if (verbose) {
96		struct statvfs sf;
97		if (statvfs(params.file, &sf) == -1)
98			err(1, "Cannot statvfs `%s'", params.file);
99
100		(void)printf( " => Adding device ID %d. (%s)\n",
101		    sb.st_dev, sf.f_mntonname);
102	}
103	dev_add(sb.st_dev);
104phase_2_end:
105	(void)memset(&params, 0, sizeof(params));
106	have_type = 0;
107}
108		|	statement eol
109		|	statement error eol {
110	yyerrok;
111}
112		;
113
114path		:	PATH {
115	(void)strlcpy(params.file, $1, MAXPATHLEN);
116}
117		;
118
119type		:	STRING {
120	if (phase == 2) {
121		if (strlen($1) >= sizeof(params.fp_type)) {
122			yyerror("Fingerprint type too long");
123			YYERROR;
124		}
125
126		(void)strlcpy(params.fp_type, $1, sizeof(params.fp_type));
127	}
128}
129		;
130
131
132fingerprint	:	STRING {
133	if (phase == 2) {
134		params.fingerprint = malloc(strlen($1) / 2);
135		if (params.fingerprint == NULL)
136			err(1, "Fingerprint mem alloc failed");
137
138		if ((params.size = convert($1, params.fingerprint)) == -1) {
139			free(params.fingerprint);
140			yyerror("Bad fingerprint");
141			YYERROR;
142		}
143	}
144
145}
146	    ;
147
148flags		:	/* empty */ {
149	if (phase == 2)
150		params.type = VERIEXEC_DIRECT;
151}
152		|	flags_spec
153		;
154
155flags_spec	:	flag_spec
156		|	flags_spec TOKEN_COMMA flag_spec
157		;
158
159flag_spec	:	STRING {
160	if (phase == 2) {
161		int field;
162		int value;
163
164		/*
165		 * XXXEE: It might be a good idea to change this into
166		 * XXXEE: something less hard-coded. Perhaps loop on
167		 * XXXEE: tuples of (name, field, value)?
168		 */
169		if (strcasecmp($1, "direct") == 0) {
170			field = FIELD_TYPE;
171			value = VERIEXEC_DIRECT;
172		} else if (strcasecmp($1, "indirect") == 0) {
173			field = FIELD_TYPE;
174			value = VERIEXEC_INDIRECT;
175		} else if (strcasecmp($1, "file") == 0) {
176			field = FIELD_TYPE;
177			value = VERIEXEC_FILE;
178		} else {
179			yyerror("Bad flag");
180			YYERROR;
181		}
182
183		switch (field) {
184		case FIELD_TYPE:
185			if (have_type) {
186				yyerror("Mulitple type definitions");
187				YYERROR;
188			}
189
190			params.type = value;
191			have_type = 1;
192			break;
193		}
194	}
195
196}
197		;
198
199eol		:	EOL
200		;
201
202%%
203
204/*
205 * Takes the hexadecimal string pointed to by "fp" and converts it to a
206 * "count" byte binary number which is stored in the array pointed to
207 * by "out".  Returns the number of bytes converted or -1 if the conversion
208 * fails.
209 */
210static int
211convert(u_char *fp, u_char *out)
212{
213	size_t i, count;
214	u_char value;
215
216	count = strlen(fp);
217
218	/*
219	 * if there are not an even number of hex digits then there is
220	 * not an integral number of bytes in the fingerprint.
221	 */
222	if ((count % 2) != 0)
223		return -1;
224
225	count /= 2;
226
227#define cvt(cv) \
228	if (isdigit(cv)) \
229		value += (cv) - '0'; \
230	else if (isxdigit(cv)) \
231		value += 10 + tolower(cv) - 'a'; \
232	else \
233		return -1
234
235	for (i = 0; i < count; i++) {
236		value = 0;
237		cvt(fp[2 * i]);
238		value <<= 4;
239		cvt(fp[2 * i + 1]);
240		out[i] = value;
241	}
242
243	return count;
244}
245