1*c525a185Skrw /* $OpenBSD: tree.c,v 1.18 2017/02/13 19:13:14 krw Exp $ */
2e853bc5dShenning
3f84e989bShshoexer /* Routines for manipulating parse trees... */
4e853bc5dShenning
5e853bc5dShenning /*
6e853bc5dShenning * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
7e853bc5dShenning * All rights reserved.
8e853bc5dShenning *
9e853bc5dShenning * Redistribution and use in source and binary forms, with or without
10e853bc5dShenning * modification, are permitted provided that the following conditions
11e853bc5dShenning * are met:
12e853bc5dShenning *
13e853bc5dShenning * 1. Redistributions of source code must retain the above copyright
14e853bc5dShenning * notice, this list of conditions and the following disclaimer.
15e853bc5dShenning * 2. Redistributions in binary form must reproduce the above copyright
16e853bc5dShenning * notice, this list of conditions and the following disclaimer in the
17e853bc5dShenning * documentation and/or other materials provided with the distribution.
18e853bc5dShenning * 3. Neither the name of The Internet Software Consortium nor the names
19e853bc5dShenning * of its contributors may be used to endorse or promote products derived
20e853bc5dShenning * from this software without specific prior written permission.
21e853bc5dShenning *
22e853bc5dShenning * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23e853bc5dShenning * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24e853bc5dShenning * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25e853bc5dShenning * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26e853bc5dShenning * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27e853bc5dShenning * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28e853bc5dShenning * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29e853bc5dShenning * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30e853bc5dShenning * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31e853bc5dShenning * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32e853bc5dShenning * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33e853bc5dShenning * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34e853bc5dShenning * SUCH DAMAGE.
35e853bc5dShenning *
36e853bc5dShenning * This software has been written for the Internet Software Consortium
37e853bc5dShenning * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38e853bc5dShenning * Enterprises. To learn more about the Internet Software Consortium,
39e853bc5dShenning * see ``http://www.vix.com/isc''. To learn more about Vixie
40e853bc5dShenning * Enterprises, see ``http://www.vix.com''.
41e853bc5dShenning */
42e853bc5dShenning
43837cddffSkrw #include <sys/types.h>
44837cddffSkrw #include <sys/socket.h>
45837cddffSkrw
46837cddffSkrw #include <net/if.h>
47837cddffSkrw
48837cddffSkrw #include <netinet/in.h>
49837cddffSkrw
50837cddffSkrw #include <stdio.h>
51837cddffSkrw #include <stdlib.h>
52837cddffSkrw #include <string.h>
53837cddffSkrw
54837cddffSkrw #include "dhcp.h"
55837cddffSkrw #include "tree.h"
56e853bc5dShenning #include "dhcpd.h"
57*c525a185Skrw #include "log.h"
58e853bc5dShenning
593c41e82cShenning static time_t tree_evaluate_recurse(int *, unsigned char **, int *,
603c41e82cShenning struct tree *);
613c41e82cShenning static void do_data_copy(int *, unsigned char **, int *, unsigned char *, int);
62e853bc5dShenning
63f84e989bShshoexer pair
cons(caddr_t car,pair cdr)64f84e989bShshoexer cons(caddr_t car, pair cdr)
65e853bc5dShenning {
66d60fc4a4Skrw pair foo;
67d60fc4a4Skrw
68d60fc4a4Skrw foo = calloc(1, sizeof *foo);
69e853bc5dShenning if (!foo)
70*c525a185Skrw fatalx("no memory for cons.");
71e853bc5dShenning foo->car = car;
72e853bc5dShenning foo->cdr = cdr;
73e853bc5dShenning return foo;
74e853bc5dShenning }
75e853bc5dShenning
76f84e989bShshoexer struct tree_cache *
tree_cache(struct tree * tree)77f84e989bShshoexer tree_cache(struct tree *tree)
78e853bc5dShenning {
79e853bc5dShenning struct tree_cache *tc;
80e853bc5dShenning
81e853bc5dShenning tc = new_tree_cache("tree_cache");
82e853bc5dShenning if (!tc)
83e853bc5dShenning return 0;
848e1c2028Sderaadt tc->value = NULL;
85e853bc5dShenning tc->len = tc->buf_size = 0;
86e853bc5dShenning tc->timeout = 0;
87e853bc5dShenning tc->tree = tree;
88e853bc5dShenning return tc;
89e853bc5dShenning }
90e853bc5dShenning
91f84e989bShshoexer struct tree *
tree_const(unsigned char * data,int len)92f84e989bShshoexer tree_const(unsigned char *data, int len)
93e853bc5dShenning {
941c629c6dSkrw unsigned char *d;
95e853bc5dShenning struct tree *nt;
96f84e989bShshoexer
971c629c6dSkrw d = calloc(1, len);
981c629c6dSkrw nt = calloc(1, sizeof(struct tree));
991c629c6dSkrw if (!nt || !d)
100*c525a185Skrw fatalx("No memory for constant data tree node.");
1011c629c6dSkrw
1021c629c6dSkrw memcpy(d, data, len);
1031c629c6dSkrw
104e853bc5dShenning nt->op = TREE_CONST;
1051c629c6dSkrw nt->data.const_val.data = d;
106e853bc5dShenning nt->data.const_val.len = len;
1071c629c6dSkrw
108e853bc5dShenning return nt;
109e853bc5dShenning }
110e853bc5dShenning
111f84e989bShshoexer struct tree *
tree_concat(struct tree * left,struct tree * right)112f84e989bShshoexer tree_concat(struct tree *left, struct tree *right)
113e853bc5dShenning {
114e853bc5dShenning struct tree *nt;
115e853bc5dShenning
116f84e989bShshoexer /*
117f84e989bShshoexer * If we're concatenating a null tree to a non-null tree, just
118f84e989bShshoexer * return the non-null tree; if both trees are null, return
119f84e989bShshoexer * a null tree.
120f84e989bShshoexer */
121e853bc5dShenning if (!left)
122e853bc5dShenning return right;
123e853bc5dShenning if (!right)
124e853bc5dShenning return left;
125e853bc5dShenning
126e853bc5dShenning /* If both trees are constant, combine them. */
127e853bc5dShenning if (left->op == TREE_CONST && right->op == TREE_CONST) {
128d60fc4a4Skrw unsigned char *buf;
129d60fc4a4Skrw
130d60fc4a4Skrw buf = calloc(1, left->data.const_val.len
131d60fc4a4Skrw + right->data.const_val.len);
132ea507cabSderaadt
133e853bc5dShenning if (!buf)
134*c525a185Skrw fatalx("No memory to concatenate constants.");
135e853bc5dShenning memcpy(buf, left->data.const_val.data,
136e853bc5dShenning left->data.const_val.len);
137e853bc5dShenning memcpy(buf + left->data.const_val.len,
138f84e989bShshoexer right->data.const_val.data, right->data.const_val.len);
13992b98df2Skrw free(left->data.const_val.data);
14092b98df2Skrw free(right->data.const_val.data);
141e853bc5dShenning left->data.const_val.data = buf;
142e853bc5dShenning left->data.const_val.len += right->data.const_val.len;
14304b89754Skrw free(right);
144e853bc5dShenning return left;
145e853bc5dShenning }
146e853bc5dShenning
147e853bc5dShenning /* Otherwise, allocate a new node to concatenate the two. */
1481c629c6dSkrw nt = calloc(1, sizeof(struct tree));
1491c629c6dSkrw if (!nt)
150*c525a185Skrw fatalx("No memory for data tree concatenation node.");
151e853bc5dShenning nt->op = TREE_CONCAT;
152e853bc5dShenning nt->data.concat.left = left;
153e853bc5dShenning nt->data.concat.right = right;
154e853bc5dShenning return nt;
155e853bc5dShenning }
156e853bc5dShenning
157f84e989bShshoexer struct tree *
tree_limit(struct tree * tree,int limit)158f84e989bShshoexer tree_limit(struct tree *tree, int limit)
159e853bc5dShenning {
160e853bc5dShenning struct tree *rv;
161e853bc5dShenning
162e853bc5dShenning /* If the tree we're limiting is constant, limit it now. */
163e853bc5dShenning if (tree->op == TREE_CONST) {
164e853bc5dShenning if (tree->data.const_val.len > limit)
165e853bc5dShenning tree->data.const_val.len = limit;
166e853bc5dShenning return tree;
167e853bc5dShenning }
168e853bc5dShenning
169e853bc5dShenning /* Otherwise, put in a node which enforces the limit on evaluation. */
1701c629c6dSkrw rv = calloc(1, sizeof(struct tree));
1711c629c6dSkrw if (!rv) {
172*c525a185Skrw log_warnx("No memory for data tree limit node.");
1738e1c2028Sderaadt return NULL;
1741c629c6dSkrw }
175e853bc5dShenning rv->op = TREE_LIMIT;
176e853bc5dShenning rv->data.limit.tree = tree;
177e853bc5dShenning rv->data.limit.limit = limit;
178e853bc5dShenning return rv;
179e853bc5dShenning }
180e853bc5dShenning
181f84e989bShshoexer int
tree_evaluate(struct tree_cache * tree_cache)182f84e989bShshoexer tree_evaluate(struct tree_cache *tree_cache)
183e853bc5dShenning {
184e853bc5dShenning unsigned char *bp = tree_cache->value;
185e853bc5dShenning int bc = tree_cache->buf_size;
186e853bc5dShenning int bufix = 0;
187e853bc5dShenning
188f84e989bShshoexer /*
189f84e989bShshoexer * If there's no tree associated with this cache, it evaluates to a
190f84e989bShshoexer * constant and that was detected at startup.
191f84e989bShshoexer */
192e853bc5dShenning if (!tree_cache->tree)
193e853bc5dShenning return 1;
194e853bc5dShenning
195e853bc5dShenning /* Try to evaluate the tree without allocating more memory... */
196e853bc5dShenning tree_cache->timeout = tree_evaluate_recurse(&bufix, &bp, &bc,
197e853bc5dShenning tree_cache->tree);
198e853bc5dShenning
199e853bc5dShenning /* No additional allocation needed? */
200e853bc5dShenning if (bufix <= bc) {
201e853bc5dShenning tree_cache->len = bufix;
202e853bc5dShenning return 1;
203e853bc5dShenning }
204e853bc5dShenning
205f84e989bShshoexer /*
206f84e989bShshoexer * If we can't allocate more memory, return with what we
207f84e989bShshoexer * have (maybe nothing).
208f84e989bShshoexer */
209d60fc4a4Skrw bp = calloc(1, bufix);
210d60fc4a4Skrw if (!bp) {
211*c525a185Skrw log_warnx("no more memory for option data");
212e853bc5dShenning return 0;
213d60fc4a4Skrw }
214e853bc5dShenning
215e853bc5dShenning /* Record the change in conditions... */
216e853bc5dShenning bc = bufix;
217e853bc5dShenning bufix = 0;
218e853bc5dShenning
219f84e989bShshoexer /*
220f84e989bShshoexer * Note that the size of the result shouldn't change on the
221f84e989bShshoexer * second call to tree_evaluate_recurse, since we haven't
222f84e989bShshoexer * changed the ``current'' time.
223f84e989bShshoexer */
224e853bc5dShenning tree_evaluate_recurse(&bufix, &bp, &bc, tree_cache->tree);
225e853bc5dShenning
226f84e989bShshoexer /*
227f84e989bShshoexer * Free the old buffer if needed, then store the new buffer
228f84e989bShshoexer * location and size and return.
229f84e989bShshoexer */
23092b98df2Skrw free(tree_cache->value);
231e853bc5dShenning tree_cache->value = bp;
232e853bc5dShenning tree_cache->len = bufix;
233e853bc5dShenning tree_cache->buf_size = bc;
234e853bc5dShenning return 1;
235e853bc5dShenning }
236e853bc5dShenning
237f84e989bShshoexer static time_t
tree_evaluate_recurse(int * bufix,unsigned char ** bufp,int * bufcount,struct tree * tree)238f84e989bShshoexer tree_evaluate_recurse(int *bufix, unsigned char **bufp,
239f84e989bShshoexer int *bufcount, struct tree *tree)
240e853bc5dShenning {
241e853bc5dShenning int limit;
242fbc5e94dShenning time_t t1, t2;
243e853bc5dShenning
244e853bc5dShenning switch (tree->op) {
245e853bc5dShenning case TREE_CONCAT:
246e853bc5dShenning t1 = tree_evaluate_recurse(bufix, bufp, bufcount,
247e853bc5dShenning tree->data.concat.left);
248e853bc5dShenning t2 = tree_evaluate_recurse(bufix, bufp, bufcount,
249e853bc5dShenning tree->data.concat.right);
250e853bc5dShenning if (t1 > t2)
251e853bc5dShenning return t2;
252e853bc5dShenning return t1;
253e853bc5dShenning
254e853bc5dShenning case TREE_CONST:
255f84e989bShshoexer do_data_copy(bufix, bufp, bufcount, tree->data.const_val.data,
256e853bc5dShenning tree->data.const_val.len);
257e853bc5dShenning t1 = MAX_TIME;
258e853bc5dShenning return t1;
259e853bc5dShenning
260e853bc5dShenning case TREE_LIMIT:
261e853bc5dShenning limit = *bufix + tree->data.limit.limit;
262e853bc5dShenning t1 = tree_evaluate_recurse(bufix, bufp, bufcount,
263e853bc5dShenning tree->data.limit.tree);
264e853bc5dShenning *bufix = limit;
265e853bc5dShenning return t1;
266e853bc5dShenning
267e853bc5dShenning default:
268*c525a185Skrw log_warnx("Bad node id in tree: %d.", tree->op);
269e853bc5dShenning t1 = MAX_TIME;
270e853bc5dShenning return t1;
271e853bc5dShenning }
272e853bc5dShenning }
273e853bc5dShenning
274f84e989bShshoexer static void
do_data_copy(int * bufix,unsigned char ** bufp,int * bufcount,unsigned char * data,int len)275f84e989bShshoexer do_data_copy(int *bufix, unsigned char **bufp, int *bufcount,
276f84e989bShshoexer unsigned char *data, int len)
277e853bc5dShenning {
278e853bc5dShenning int space = *bufcount - *bufix;
279e853bc5dShenning
280e853bc5dShenning /* If there's more space than we need, use only what we need. */
281e853bc5dShenning if (space > len)
282e853bc5dShenning space = len;
283e853bc5dShenning
284f84e989bShshoexer /*
285f84e989bShshoexer * Copy as much data as will fit, then increment the buffer index
286f84e989bShshoexer * by the amount we actually had to copy, which could be more.
287f84e989bShshoexer */
288e853bc5dShenning if (space > 0)
289e853bc5dShenning memcpy(*bufp + *bufix, data, space);
290e853bc5dShenning *bufix += len;
291e853bc5dShenning }
292