1/*	$NetBSD$	*/
2
3/*
4 * Copyright (c) 2008 Kungliga Tekniska H��gskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "hx_locl.h"
37
38struct hx_expr *
39_hx509_make_expr(enum hx_expr_op op, void *arg1, void *arg2)
40{
41    struct hx_expr *expr;
42
43    expr = malloc(sizeof(*expr));
44    if (expr == NULL)
45	return NULL;
46    expr->op = op;
47    expr->arg1 = arg1;
48    expr->arg2 = arg2;
49
50    return expr;
51}
52
53static const char *
54eval_word(hx509_context context, hx509_env env, struct hx_expr *word)
55{
56    switch (word->op) {
57    case expr_STRING:
58	return word->arg1;
59    case expr_VAR:
60	if (word->arg2 == NULL)
61	    return hx509_env_find(context, env, word->arg1);
62
63	env = hx509_env_find_binding(context, env, word->arg1);
64	if (env == NULL)
65	    return NULL;
66
67	return eval_word(context, env, word->arg2);
68    default:
69	return NULL;
70    }
71}
72
73static hx509_env
74find_variable(hx509_context context, hx509_env env, struct hx_expr *word)
75{
76    assert(word->op == expr_VAR);
77
78    if (word->arg2 == NULL)
79	return hx509_env_find_binding(context, env, word->arg1);
80
81    env = hx509_env_find_binding(context, env, word->arg1);
82    if (env == NULL)
83	return NULL;
84    return find_variable(context, env, word->arg2);
85}
86
87static int
88eval_comp(hx509_context context, hx509_env env, struct hx_expr *expr)
89{
90    switch (expr->op) {
91    case comp_NE:
92    case comp_EQ:
93    case comp_TAILEQ: {
94	const char *s1, *s2;
95	int ret;
96
97	s1 = eval_word(context, env, expr->arg1);
98	s2 = eval_word(context, env, expr->arg2);
99
100	if (s1 == NULL || s2 == NULL)
101	    return FALSE;
102
103	if (expr->op == comp_TAILEQ) {
104	    size_t len1 = strlen(s1);
105	    size_t len2 = strlen(s2);
106
107	    if (len1 < len2)
108		return 0;
109	    ret = strcmp(s1 + (len1 - len2), s2) == 0;
110	} else {
111	    ret = strcmp(s1, s2) == 0;
112	    if (expr->op == comp_NE)
113		ret = !ret;
114	}
115	return ret;
116    }
117    case comp_IN: {
118	struct hx_expr *subexpr;
119	const char *w, *s1;
120
121	w = eval_word(context, env, expr->arg1);
122
123	subexpr = expr->arg2;
124
125	if (subexpr->op == expr_WORDS) {
126	    while (subexpr) {
127		s1 = eval_word(context, env, subexpr->arg1);
128		if (strcmp(w, s1) == 0)
129		    return TRUE;
130		subexpr = subexpr->arg2;
131	    }
132	} else if (subexpr->op == expr_VAR) {
133	    hx509_env subenv;
134
135	    subenv = find_variable(context, env, subexpr);
136	    if (subenv == NULL)
137		return FALSE;
138
139	    while (subenv) {
140		if (subenv->type != env_string)
141		    continue;
142		if (strcmp(w, subenv->name) == 0)
143		    return TRUE;
144		if (strcmp(w, subenv->u.string) == 0)
145		    return TRUE;
146		subenv = subenv->next;
147	    }
148
149	} else
150	    _hx509_abort("hx509 eval IN unknown op: %d", (int)subexpr->op);
151
152	return FALSE;
153    }
154    default:
155	_hx509_abort("hx509 eval expr with unknown op: %d", (int)expr->op);
156    }
157    return FALSE;
158}
159
160int
161_hx509_expr_eval(hx509_context context, hx509_env env, struct hx_expr *expr)
162{
163    switch (expr->op) {
164    case op_TRUE:
165	return 1;
166    case op_FALSE:
167	return 0;
168    case op_NOT:
169	return ! _hx509_expr_eval(context, env, expr->arg1);
170    case op_AND:
171	return _hx509_expr_eval(context, env, expr->arg1) &&
172	    _hx509_expr_eval(context, env, expr->arg2);
173    case op_OR:
174	return _hx509_expr_eval(context, env, expr->arg1) ||
175	    _hx509_expr_eval(context, env, expr->arg2);
176    case op_COMP:
177	return eval_comp(context, env, expr->arg1);
178    default:
179	_hx509_abort("hx509 eval expr with unknown op: %d", (int)expr->op);
180	UNREACHABLE(return 0);
181    }
182}
183
184void
185_hx509_expr_free(struct hx_expr *expr)
186{
187    switch (expr->op) {
188    case expr_STRING:
189    case expr_NUMBER:
190	free(expr->arg1);
191	break;
192    case expr_WORDS:
193    case expr_FUNCTION:
194    case expr_VAR:
195	free(expr->arg1);
196	if (expr->arg2)
197	    _hx509_expr_free(expr->arg2);
198	break;
199    default:
200	if (expr->arg1)
201	    _hx509_expr_free(expr->arg1);
202	if (expr->arg2)
203	    _hx509_expr_free(expr->arg2);
204	break;
205    }
206    free(expr);
207}
208
209struct hx_expr *
210_hx509_expr_parse(const char *buf)
211{
212    _hx509_expr_input.buf = buf;
213    _hx509_expr_input.length = strlen(buf);
214    _hx509_expr_input.offset = 0;
215    _hx509_expr_input.expr = NULL;
216
217    if (_hx509_expr_input.error) {
218	free(_hx509_expr_input.error);
219	_hx509_expr_input.error = NULL;
220    }
221
222    yyparse();
223
224    return _hx509_expr_input.expr;
225}
226
227void
228_hx509_sel_yyerror (char *s)
229{
230     if (_hx509_expr_input.error)
231         free(_hx509_expr_input.error);
232
233     _hx509_expr_input.error = strdup(s);
234}
235
236