1%{
2/*	$NetBSD: veriexecctl_parse.y,v 1.25 2008/08/31 23:37:45 dholland Exp $	*/
3
4/*-
5 * Copyright 2005 Elad Efrat <elad@NetBSD.org>
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/stat.h>
35#include <sys/verified_exec.h>
36
37#include <ctype.h>
38#include <stdio.h>
39#include <string.h>
40#include <err.h>
41#include <stdbool.h>
42#include <prop/proplib.h>
43
44#include "veriexecctl.h"
45
46extern int yylex(void);
47extern size_t line;
48extern int verbose, error;
49
50bool keep_filename = false, eval_on_load = false;
51prop_dictionary_t load_params;
52
53%}
54
55%union {
56	char *string;
57}
58
59%token <string> PATH
60%token <string> STRING
61%token EOL TOKEN_COMMA
62
63%%
64
65statement	:	/* empty */
66		|	statement path type fingerprint flags eol {
67	extern int gfd;
68	struct stat sb;
69
70	if (stat(dict_gets(load_params, "file"), &sb) == -1) {
71		if (verbose)
72			warnx("Line %zu: Can't stat `%s'", line,
73			    dict_gets(load_params, "file"));
74		error = EXIT_FAILURE;
75		goto skip;
76	}
77
78	/* Only regular files */
79	if (!S_ISREG(sb.st_mode)) {
80		if (verbose)
81			warnx("Line %zu: %s is not a regular file", line,
82			    dict_gets(load_params, "file"));
83		error = EXIT_FAILURE;
84		goto skip;
85	}
86
87	if (verbose) {
88		(void)printf( "Adding file `%s'.\n",
89		    dict_gets(load_params, "file"));
90	}
91
92	prop_dictionary_set(load_params, "keep-filename",
93	    prop_bool_create(keep_filename));
94
95	prop_dictionary_set(load_params, "eval-on-load",
96	    prop_bool_create(eval_on_load));
97
98	if (prop_dictionary_send_ioctl(load_params, gfd, VERIEXEC_LOAD) != 0) {
99		if (verbose)
100			warn("Cannot load params from `%s'",
101			    dict_gets(load_params, "file"));
102		error = EXIT_FAILURE;
103	}
104
105 skip:
106	prop_object_release(load_params);
107	load_params = NULL;
108}
109		|	statement eol
110		|	statement error eol {
111	yyerrok;
112}
113		;
114
115path		:	PATH {
116	if (load_params == NULL)
117		load_params = prop_dictionary_create();
118
119	dict_sets(load_params, "file", $1);
120}
121		;
122
123type		:	STRING {
124	dict_sets(load_params, "fp-type", $1);
125}
126		;
127
128
129fingerprint	:	STRING {
130	u_char *fp;
131	size_t n;
132
133	fp = malloc(strlen($1) / 2);
134	if (fp == NULL)
135		err(1, "Cannot allocate memory for fingerprint");
136
137	n = convert($1, fp);
138	if (n == (size_t)-1) {
139		free(fp);
140		if (verbose)
141			warnx("Bad fingerprint `%s' in line %zu", $1, line);
142		error = EXIT_FAILURE;
143		YYERROR;
144	}
145
146	dict_setd(load_params, "fp", fp, n);
147	free(fp);
148}
149	    ;
150
151flags		:	/* empty */
152		|	flags_spec
153		;
154
155flags_spec	:	flag_spec
156		|	flags_spec TOKEN_COMMA flag_spec
157		;
158
159flag_spec	:	STRING {
160	uint8_t t = 0;
161
162	prop_dictionary_get_uint8(load_params, "entry-type", &t);
163
164	if (strcasecmp($1, "direct") == 0) {
165		t |= VERIEXEC_DIRECT;
166	} else if (strcasecmp($1, "indirect") == 0) {
167		t |= VERIEXEC_INDIRECT;
168	} else if (strcasecmp($1, "file") == 0) {
169		t |= VERIEXEC_FILE;
170	} else if (strcasecmp($1, "program") == 0) {
171		t |= VERIEXEC_DIRECT;
172	} else if (strcasecmp($1, "interpreter") == 0) {
173		t |= VERIEXEC_INDIRECT;
174	} else if (strcasecmp($1, "script") == 0) {
175		t |= (VERIEXEC_FILE | VERIEXEC_DIRECT);
176	} else if (strcasecmp($1, "library") == 0) {
177		t |= (VERIEXEC_FILE | VERIEXEC_INDIRECT);
178	} else if (strcasecmp($1, "untrusted") == 0) {
179		t |= VERIEXEC_UNTRUSTED;
180	} else {
181		if (verbose)
182			warnx("Bad flag `%s' in line %zu", $1, line);
183		error = EXIT_FAILURE;
184		YYERROR;
185	}
186
187	prop_dictionary_set_uint8(load_params, "entry-type", t);
188}
189		;
190
191eol		:	EOL
192		;
193
194%%
195
196/*
197 * Takes the hexadecimal string pointed to by "fp" and converts it to a
198 * "count" byte binary number which is stored in the array pointed to
199 * by "out".  Returns the number of bytes converted or -1 if the conversion
200 * fails.
201 */
202static size_t
203convert(char *fp, u_char *out)
204{
205	size_t i, count;
206	u_char value;
207
208	count = strlen(fp);
209
210	/*
211	 * if there are not an even number of hex digits then there is
212	 * not an integral number of bytes in the fingerprint.
213	 */
214	if ((count % 2) != 0)
215		return (size_t)-1;
216
217	count /= 2;
218
219#define cvt(cv) \
220	if (isdigit((unsigned char) cv)) \
221		value += (cv) - '0'; \
222	else if (isxdigit((unsigned char) cv)) \
223		value += 10 + tolower((unsigned char) cv) - 'a'; \
224	else \
225		return (size_t)-1
226
227	for (i = 0; i < count; i++) {
228		value = 0;
229		cvt(fp[2 * i]);
230		value <<= 4;
231		cvt(fp[2 * i + 1]);
232		out[i] = value;
233	}
234
235	return count;
236}
237
238static void
239yyerror(const char *msg)
240{
241	if (verbose)
242		warnx("%s in line %zu", msg, line);
243}
244