]>
Commit | Line | Data |
---|---|---|
d7837182 TL |
1 | /* tree.c |
2 | ||
3 | Routines for manipulating parse trees... */ | |
4 | ||
5 | /* | |
88cd8aca | 6 | * Copyright (c) 2004-2006 by Internet Systems Consortium, Inc. ("ISC") |
98311e4b | 7 | * Copyright (c) 1995-2003 by Internet Software Consortium |
d7837182 | 8 | * |
98311e4b DH |
9 | * Permission to use, copy, modify, and distribute this software for any |
10 | * purpose with or without fee is hereby granted, provided that the above | |
11 | * copyright notice and this permission notice appear in all copies. | |
d7837182 | 12 | * |
98311e4b DH |
13 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES |
14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR | |
16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | |
19 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
d7837182 | 20 | * |
98311e4b DH |
21 | * Internet Systems Consortium, Inc. |
22 | * 950 Charter Street | |
23 | * Redwood City, CA 94063 | |
24 | * <info@isc.org> | |
25 | * http://www.isc.org/ | |
49733f31 | 26 | * |
98311e4b | 27 | * This software has been written for Internet Systems Consortium |
49733f31 | 28 | * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. |
98311e4b | 29 | * To learn more about Internet Systems Consortium, see |
49733f31 TL |
30 | * ``http://www.isc.org/''. To learn more about Vixie Enterprises, |
31 | * see ``http://www.vix.com''. To learn more about Nominum, Inc., see | |
32 | * ``http://www.nominum.com''. | |
d7837182 TL |
33 | */ |
34 | ||
35 | #ifndef lint | |
36 | static char copyright[] = | |
fe5b0fdd | 37 | "$Id: tree.c,v 1.114 2007/05/19 18:47:14 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; |
d7837182 TL |
38 | #endif /* not lint */ |
39 | ||
40 | #include "dhcpd.h" | |
4bd8800e | 41 | #include <omapip/omapip_p.h> |
2727c1cf | 42 | #include <ctype.h> |
fe5b0fdd | 43 | #include <sys/wait.h> |
4bd8800e | 44 | |
6ceb9118 | 45 | struct binding_scope *global_scope; |
d7837182 | 46 | |
1d07a807 TL |
47 | static int do_host_lookup PROTO ((struct data_string *, |
48 | struct dns_host_entry *)); | |
d7837182 | 49 | |
7167c654 TL |
50 | #ifdef NSUPDATE |
51 | struct __res_state resolver_state; | |
79c36eb7 | 52 | int resolver_inited = 0; |
7167c654 TL |
53 | #endif |
54 | ||
b543fea9 DH |
55 | static void |
56 | append_to_ary(char **ary_ptr, int *ary_size, int ary_capacity, | |
57 | char *new_element) | |
58 | { | |
59 | /* INSIST(ary_ptr != NULL); */ | |
60 | /* INSIST(ary_size != NULL); */ | |
61 | /* INSIST(ary_capacity > 1); */ | |
62 | ||
63 | if (new_element == NULL) | |
64 | return; | |
65 | ||
66 | if (*ary_size >= ary_capacity) { | |
67 | log_fatal("Improbable error at %s:%d.", MDL); | |
68 | return; | |
69 | } | |
70 | ||
71 | ary_ptr[(*ary_size)++] = new_element; | |
72 | } | |
73 | ||
74 | static char * | |
75 | data_string_to_char_string(struct data_string *d) | |
76 | { | |
77 | char *str, *start, *end; | |
78 | const unsigned char *pos; | |
79 | int len; | |
80 | ||
81 | if (d == NULL); | |
82 | return NULL; | |
83 | ||
84 | pos = d->data; | |
85 | ||
86 | if (pos == NULL) | |
87 | return NULL; | |
88 | ||
89 | /* Per byte could be "\777" at worst, plus null terminator. */ | |
90 | len = (d->len * 4) + 1; | |
91 | str = dmalloc(len, MDL); | |
92 | if (!str) | |
93 | return NULL; | |
94 | ||
95 | start = str; | |
96 | end = start + len; | |
97 | ||
98 | if (pretty_escape(&start, end, &pos, pos + d->len) < 0) { | |
99 | dfree(str, MDL); | |
100 | return NULL; | |
101 | } | |
102 | ||
103 | /* dmalloc() sets the buffer to zero - there is no need to null | |
104 | * terminate. | |
105 | */ | |
106 | ||
107 | return str; | |
108 | } | |
109 | ||
98bd7ca0 DH |
110 | #define DS_SPRINTF_SIZE 128 |
111 | ||
112 | /* | |
113 | * If we are using a data_string structure to hold a NUL-terminated | |
114 | * ASCII string, this function can be used to append a printf-formatted | |
115 | * string to the end of it. The data_string structure will be resized to | |
116 | * be big enough to hold the new string. | |
117 | * | |
118 | * If the append works, then 1 is returned. | |
119 | * | |
120 | * If it is not possible to allocate a buffer big enough to hold the | |
121 | * new value, then the old data_string is unchanged, and 0 is returned. | |
122 | */ | |
123 | int | |
124 | data_string_sprintfa(struct data_string *ds, const char *fmt, ...) { | |
125 | va_list args; | |
126 | int cur_strlen; | |
127 | int max; | |
128 | int vsnprintf_ret; | |
129 | int new_len; | |
130 | struct buffer *tmp_buffer; | |
131 | ||
132 | /* | |
133 | * If the data_string is empty, then initialize it. | |
134 | */ | |
135 | if (ds->data == NULL) { | |
136 | /* INSIST(ds.buffer == NULL); */ | |
137 | if (!buffer_allocate(&ds->buffer, DS_SPRINTF_SIZE, MDL)) { | |
138 | return 0; | |
139 | } | |
140 | ds->data = ds->buffer->data; | |
141 | ds->len = DS_SPRINTF_SIZE; | |
142 | *((char *)ds->data) = '\0'; | |
143 | } | |
144 | ||
145 | /* | |
146 | * Get the length of the string, and figure out how much space | |
147 | * is left. | |
148 | */ | |
149 | cur_strlen = strlen(ds->data); | |
150 | max = ds->len - cur_strlen; | |
151 | ||
152 | /* | |
153 | * Use vsnprintf(), which won't write past our space, but will | |
154 | * tell us how much space it wants. | |
155 | */ | |
156 | va_start(args, fmt); | |
157 | vsnprintf_ret = vsnprintf((char *)ds->data+cur_strlen, max, fmt, args); | |
158 | /* INSIST(vsnprintf_ret >= 0); */ | |
159 | ||
160 | /* | |
161 | * If our buffer is not big enough, we need a new buffer. | |
162 | */ | |
163 | if (vsnprintf_ret >= max) { | |
164 | /* | |
165 | * Figure out a size big enough. | |
166 | */ | |
167 | new_len = ds->len * 2; | |
168 | while (new_len <= cur_strlen + vsnprintf_ret) { | |
169 | new_len *= 2; | |
170 | } | |
171 | ||
172 | /* | |
173 | * Create a new buffer and fill it. | |
174 | */ | |
175 | tmp_buffer = NULL; | |
176 | if (!buffer_allocate(&tmp_buffer, new_len, MDL)) { | |
177 | /* | |
178 | * If we can't create a big enough buffer, | |
179 | * we should remove any truncated output that we had. | |
180 | */ | |
181 | *((char *)ds->data+cur_strlen) = '\0'; | |
182 | va_end(args); | |
183 | return 0; | |
184 | } | |
185 | memcpy(tmp_buffer->data, ds->data, cur_strlen); | |
186 | vsprintf(tmp_buffer->data + cur_strlen, fmt, args); | |
187 | ||
188 | /* | |
189 | * Replace our old buffer with the new buffer. | |
190 | */ | |
191 | buffer_dereference(&ds->buffer, MDL); | |
192 | buffer_reference(&ds->buffer, tmp_buffer, MDL); | |
193 | buffer_dereference(&tmp_buffer, MDL); | |
194 | ds->data = ds->buffer->data; | |
195 | ds->len = new_len; | |
196 | } | |
197 | va_end(args); | |
198 | return 1; | |
199 | } | |
200 | ||
d7837182 TL |
201 | pair cons (car, cdr) |
202 | caddr_t car; | |
203 | pair cdr; | |
204 | { | |
4cbc378f | 205 | pair foo = (pair)dmalloc (sizeof *foo, MDL); |
d7837182 | 206 | if (!foo) |
8ae2d595 | 207 | log_fatal ("no memory for cons."); |
d7837182 TL |
208 | foo -> car = car; |
209 | foo -> cdr = cdr; | |
210 | return foo; | |
211 | } | |
212 | ||
4bd8800e | 213 | int make_const_option_cache (oc, buffer, data, len, option, file, line) |
1d07a807 TL |
214 | struct option_cache **oc; |
215 | struct buffer **buffer; | |
216 | u_int8_t *data; | |
b1b7b521 | 217 | unsigned len; |
1d07a807 | 218 | struct option *option; |
4bd8800e TL |
219 | const char *file; |
220 | int line; | |
d7837182 | 221 | { |
1d07a807 TL |
222 | struct buffer *bp; |
223 | ||
224 | if (buffer) { | |
225 | bp = *buffer; | |
226 | *buffer = 0; | |
227 | } else { | |
228 | bp = (struct buffer *)0; | |
4bd8800e TL |
229 | if (!buffer_allocate (&bp, len, file, line)) { |
230 | log_error ("%s(%d): can't allocate buffer.", | |
231 | file, line); | |
cd038e3e TL |
232 | return 0; |
233 | } | |
1d07a807 TL |
234 | } |
235 | ||
4bd8800e TL |
236 | if (!option_cache_allocate (oc, file, line)) { |
237 | log_error ("%s(%d): can't allocate option cache.", file, line); | |
238 | buffer_dereference (&bp, file, line); | |
1d07a807 TL |
239 | return 0; |
240 | } | |
241 | ||
242 | (*oc) -> data.len = len; | |
98311e4b | 243 | (*oc) -> data.buffer = bp; |
1d07a807 TL |
244 | (*oc) -> data.data = &bp -> data [0]; |
245 | (*oc) -> data.terminated = 0; | |
246 | if (data) | |
b1b7b521 | 247 | memcpy (&bp -> data [0], data, len); |
66c8f734 | 248 | option_reference(&((*oc)->option), option, MDL); |
1d07a807 | 249 | return 1; |
d7837182 TL |
250 | } |
251 | ||
1d07a807 TL |
252 | int make_host_lookup (expr, name) |
253 | struct expression **expr; | |
b1b7b521 | 254 | const char *name; |
d7837182 | 255 | { |
4cbc378f | 256 | if (!expression_allocate (expr, MDL)) { |
8ae2d595 | 257 | log_error ("No memory for host lookup tree node."); |
1d07a807 TL |
258 | return 0; |
259 | } | |
260 | (*expr) -> op = expr_host_lookup; | |
261 | if (!enter_dns_host (&((*expr) -> data.host_lookup), name)) { | |
4cbc378f | 262 | expression_dereference (expr, MDL); |
1d07a807 TL |
263 | return 0; |
264 | } | |
265 | return 1; | |
266 | } | |
33e712ea | 267 | |
1d07a807 TL |
268 | int enter_dns_host (dh, name) |
269 | struct dns_host_entry **dh; | |
b1b7b521 | 270 | const char *name; |
1d07a807 TL |
271 | { |
272 | /* XXX This should really keep a hash table of hostnames | |
273 | XXX and just add a new reference to a hostname that | |
274 | XXX already exists, if possible, rather than creating | |
275 | XXX a new structure. */ | |
4cbc378f | 276 | if (!dns_host_entry_allocate (dh, name, MDL)) { |
8ae2d595 | 277 | log_error ("Can't allocate space for new host."); |
1d07a807 TL |
278 | return 0; |
279 | } | |
280 | return 1; | |
d7837182 TL |
281 | } |
282 | ||
d758ad8c TL |
283 | int make_const_data (struct expression **expr, const unsigned char *data, |
284 | unsigned len, int terminated, int allocate, | |
285 | const char *file, int line) | |
d7837182 | 286 | { |
33e712ea | 287 | struct expression *nt; |
1d07a807 | 288 | |
d758ad8c | 289 | if (!expression_allocate (expr, file, line)) { |
8ae2d595 | 290 | log_error ("No memory for make_const_data tree node."); |
1d07a807 TL |
291 | return 0; |
292 | } | |
293 | nt = *expr; | |
294 | ||
6f76b6ac | 295 | if (len) { |
33e712ea | 296 | if (allocate) { |
1d07a807 | 297 | if (!buffer_allocate (&nt -> data.const_data.buffer, |
d758ad8c | 298 | len + terminated, file, line)) { |
dd6e44a5 | 299 | log_error ("Can't allocate const_data buffer"); |
d758ad8c | 300 | expression_dereference (expr, file, line); |
1d07a807 TL |
301 | return 0; |
302 | } | |
303 | nt -> data.const_data.data = | |
304 | &nt -> data.const_data.buffer -> data [0]; | |
b1b7b521 | 305 | memcpy (nt -> data.const_data.buffer -> data, |
33e712ea | 306 | data, len + terminated); |
1d07a807 | 307 | } else |
33e712ea TL |
308 | nt -> data.const_data.data = data; |
309 | nt -> data.const_data.terminated = terminated; | |
6f76b6ac | 310 | } else |
33e712ea | 311 | nt -> data.const_data.data = 0; |
6f76b6ac | 312 | |
33e712ea TL |
313 | nt -> op = expr_const_data; |
314 | nt -> data.const_data.len = len; | |
1d07a807 | 315 | return 1; |
d7837182 TL |
316 | } |
317 | ||
4cbc378f TL |
318 | int make_const_int (expr, val) |
319 | struct expression **expr; | |
320 | unsigned long val; | |
321 | { | |
322 | if (!expression_allocate (expr, MDL)) { | |
d758ad8c | 323 | log_error ("No memory for make_const_int tree node."); |
4cbc378f TL |
324 | return 0; |
325 | } | |
326 | ||
327 | (*expr) -> op = expr_const_int; | |
328 | (*expr) -> data.const_int = val; | |
329 | return 1; | |
330 | } | |
331 | ||
1d07a807 TL |
332 | int make_concat (expr, left, right) |
333 | struct expression **expr; | |
33e712ea | 334 | struct expression *left, *right; |
d7837182 | 335 | { |
d7837182 TL |
336 | /* If we're concatenating a null tree to a non-null tree, just |
337 | return the non-null tree; if both trees are null, return | |
338 | a null tree. */ | |
1d07a807 TL |
339 | if (!left) { |
340 | if (!right) | |
341 | return 0; | |
4cbc378f | 342 | expression_reference (expr, right, MDL); |
1d07a807 TL |
343 | return 1; |
344 | } | |
345 | if (!right) { | |
4cbc378f | 346 | expression_reference (expr, left, MDL); |
1d07a807 | 347 | return 1; |
d7837182 TL |
348 | } |
349 | ||
350 | /* Otherwise, allocate a new node to concatenate the two. */ | |
4cbc378f | 351 | if (!expression_allocate (expr, MDL)) { |
8ae2d595 | 352 | log_error ("No memory for concatenation expression node."); |
1d07a807 TL |
353 | return 0; |
354 | } | |
355 | ||
356 | (*expr) -> op = expr_concat; | |
4cbc378f TL |
357 | expression_reference (&(*expr) -> data.concat [0], left, MDL); |
358 | expression_reference (&(*expr) -> data.concat [1], right, MDL); | |
1d07a807 | 359 | return 1; |
d7837182 TL |
360 | } |
361 | ||
dd6e44a5 TL |
362 | int make_encapsulation (expr, name) |
363 | struct expression **expr; | |
364 | struct data_string *name; | |
365 | { | |
366 | /* Allocate a new node to store the encapsulation. */ | |
4cbc378f | 367 | if (!expression_allocate (expr, MDL)) { |
dd6e44a5 TL |
368 | log_error ("No memory for encapsulation expression node."); |
369 | return 0; | |
370 | } | |
371 | ||
372 | (*expr) -> op = expr_encapsulate; | |
4cbc378f | 373 | data_string_copy (&(*expr) -> data.encapsulate, name, MDL); |
dd6e44a5 TL |
374 | return 1; |
375 | } | |
376 | ||
1d07a807 TL |
377 | int make_substring (new, expr, offset, length) |
378 | struct expression **new; | |
33e712ea TL |
379 | struct expression *expr; |
380 | struct expression *offset; | |
381 | struct expression *length; | |
d7837182 | 382 | { |
1d07a807 | 383 | /* Allocate an expression node to compute the substring. */ |
4cbc378f | 384 | if (!expression_allocate (new, MDL)) { |
8ae2d595 | 385 | log_error ("no memory for substring expression."); |
1d07a807 | 386 | return 0; |
d7837182 | 387 | } |
1d07a807 | 388 | (*new) -> op = expr_substring; |
4cbc378f TL |
389 | expression_reference (&(*new) -> data.substring.expr, expr, MDL); |
390 | expression_reference (&(*new) -> data.substring.offset, offset, MDL); | |
391 | expression_reference (&(*new) -> data.substring.len, length, MDL); | |
1d07a807 | 392 | return 1; |
d7837182 TL |
393 | } |
394 | ||
1d07a807 TL |
395 | int make_limit (new, expr, limit) |
396 | struct expression **new; | |
33e712ea TL |
397 | struct expression *expr; |
398 | int limit; | |
d7837182 | 399 | { |
33e712ea TL |
400 | struct expression *rv; |
401 | ||
1d07a807 | 402 | /* Allocate a node to enforce a limit on evaluation. */ |
4cbc378f | 403 | if (!expression_allocate (new, MDL)) |
8ae2d595 | 404 | log_error ("no memory for limit expression"); |
1d07a807 | 405 | (*new) -> op = expr_substring; |
4cbc378f | 406 | expression_reference (&(*new) -> data.substring.expr, expr, MDL); |
33e712ea TL |
407 | |
408 | /* Offset is a constant 0. */ | |
4cbc378f | 409 | if (!expression_allocate (&(*new) -> data.substring.offset, MDL)) { |
8ae2d595 | 410 | log_error ("no memory for limit offset expression"); |
4cbc378f | 411 | expression_dereference (new, MDL); |
1d07a807 TL |
412 | return 0; |
413 | } | |
414 | (*new) -> data.substring.offset -> op = expr_const_int; | |
415 | (*new) -> data.substring.offset -> data.const_int = 0; | |
33e712ea TL |
416 | |
417 | /* Length is a constant: the specified limit. */ | |
4cbc378f | 418 | if (!expression_allocate (&(*new) -> data.substring.len, MDL)) { |
8ae2d595 | 419 | log_error ("no memory for limit length expression"); |
4cbc378f | 420 | expression_dereference (new, MDL); |
1d07a807 TL |
421 | return 0; |
422 | } | |
423 | (*new) -> data.substring.len -> op = expr_const_int; | |
424 | (*new) -> data.substring.len -> data.const_int = limit; | |
425 | ||
426 | return 1; | |
d7837182 TL |
427 | } |
428 | ||
d758ad8c TL |
429 | int option_cache (struct option_cache **oc, struct data_string *dp, |
430 | struct expression *expr, struct option *option, | |
431 | const char *file, int line) | |
d7837182 | 432 | { |
d758ad8c | 433 | if (!option_cache_allocate (oc, file, line)) |
1d07a807 TL |
434 | return 0; |
435 | if (dp) | |
d758ad8c | 436 | data_string_copy (&(*oc) -> data, dp, file, line); |
1d07a807 | 437 | if (expr) |
d758ad8c | 438 | expression_reference (&(*oc) -> expression, expr, file, line); |
f7fdb216 | 439 | option_reference(&(*oc)->option, option, MDL); |
1d07a807 | 440 | return 1; |
d7837182 TL |
441 | } |
442 | ||
4cbc378f TL |
443 | int make_let (result, name) |
444 | struct executable_statement **result; | |
445 | const char *name; | |
446 | { | |
447 | if (!(executable_statement_allocate (result, MDL))) | |
448 | return 0; | |
449 | ||
450 | (*result) -> op = let_statement; | |
451 | (*result) -> data.let.name = dmalloc (strlen (name) + 1, MDL); | |
452 | if (!(*result) -> data.let.name) { | |
453 | executable_statement_dereference (result, MDL); | |
454 | return 0; | |
455 | } | |
456 | strcpy ((*result) -> data.let.name, name); | |
457 | return 1; | |
458 | } | |
459 | ||
3175ee90 | 460 | static int do_host_lookup (result, dns) |
1d07a807 | 461 | struct data_string *result; |
d7837182 TL |
462 | struct dns_host_entry *dns; |
463 | { | |
464 | struct hostent *h; | |
b1b7b521 TL |
465 | unsigned i, count; |
466 | unsigned new_len; | |
33e712ea | 467 | |
65bf41da | 468 | #ifdef DEBUG_EVAL |
4cbc378f | 469 | log_debug ("time: now = %d dns = %d diff = %d", |
d7837182 | 470 | cur_time, dns -> timeout, cur_time - dns -> timeout); |
65bf41da | 471 | #endif |
d7837182 TL |
472 | |
473 | /* If the record hasn't timed out, just copy the data and return. */ | |
474 | if (cur_time <= dns -> timeout) { | |
65bf41da | 475 | #ifdef DEBUG_EVAL |
8ae2d595 | 476 | log_debug ("easy copy: %d %s", |
1d07a807 TL |
477 | dns -> data.len, |
478 | (dns -> data.len > 4 | |
479 | ? inet_ntoa (*(struct in_addr *)(dns -> data.data)) | |
480 | : 0)); | |
65bf41da | 481 | #endif |
4cbc378f | 482 | data_string_copy (result, &dns -> data, MDL); |
1d07a807 | 483 | return 1; |
d7837182 | 484 | } |
65bf41da | 485 | #ifdef DEBUG_EVAL |
8ae2d595 | 486 | log_debug ("Looking up %s", dns -> hostname); |
65bf41da | 487 | #endif |
d7837182 TL |
488 | |
489 | /* Otherwise, look it up... */ | |
490 | h = gethostbyname (dns -> hostname); | |
491 | if (!h) { | |
fc28acef | 492 | #ifndef NO_H_ERRNO |
d7837182 TL |
493 | switch (h_errno) { |
494 | case HOST_NOT_FOUND: | |
fc28acef | 495 | #endif |
8ae2d595 | 496 | log_error ("%s: host unknown.", dns -> hostname); |
fc28acef | 497 | #ifndef NO_H_ERRNO |
d7837182 TL |
498 | break; |
499 | case TRY_AGAIN: | |
8ae2d595 | 500 | log_error ("%s: temporary name server failure", |
fa098be8 | 501 | dns -> hostname); |
d7837182 TL |
502 | break; |
503 | case NO_RECOVERY: | |
8ae2d595 | 504 | log_error ("%s: name server failed", dns -> hostname); |
d7837182 TL |
505 | break; |
506 | case NO_DATA: | |
8ae2d595 | 507 | log_error ("%s: no A record associated with address", |
fa098be8 | 508 | dns -> hostname); |
d7837182 | 509 | } |
fc28acef | 510 | #endif /* !NO_H_ERRNO */ |
d7837182 TL |
511 | |
512 | /* Okay to try again after a minute. */ | |
33e712ea | 513 | dns -> timeout = cur_time + 60; |
4cbc378f | 514 | data_string_forget (&dns -> data, MDL); |
1d07a807 | 515 | return 0; |
d7837182 TL |
516 | } |
517 | ||
65bf41da | 518 | #ifdef DEBUG_EVAL |
8ae2d595 | 519 | log_debug ("Lookup succeeded; first address is %s", |
33e712ea | 520 | inet_ntoa (h -> h_addr_list [0])); |
65bf41da | 521 | #endif |
d7837182 TL |
522 | |
523 | /* Count the number of addresses we got... */ | |
1d07a807 | 524 | for (count = 0; h -> h_addr_list [count]; count++) |
d7837182 TL |
525 | ; |
526 | ||
1d07a807 | 527 | /* Dereference the old data, if any. */ |
4cbc378f | 528 | data_string_forget (&dns -> data, MDL); |
1d07a807 | 529 | |
d7837182 | 530 | /* Do we need to allocate more memory? */ |
1d07a807 | 531 | new_len = count * h -> h_length; |
4cbc378f | 532 | if (!buffer_allocate (&dns -> data.buffer, new_len, MDL)) |
1d07a807 | 533 | { |
8ae2d595 | 534 | log_error ("No memory for %s.", dns -> hostname); |
1d07a807 | 535 | return 0; |
d7837182 TL |
536 | } |
537 | ||
1d07a807 TL |
538 | dns -> data.data = &dns -> data.buffer -> data [0]; |
539 | dns -> data.len = new_len; | |
540 | dns -> data.terminated = 0; | |
541 | ||
d7837182 TL |
542 | /* Addresses are conveniently stored one to the buffer, so we |
543 | have to copy them out one at a time... :'( */ | |
1d07a807 | 544 | for (i = 0; i < count; i++) { |
b1b7b521 TL |
545 | memcpy (&dns -> data.buffer -> data [h -> h_length * i], |
546 | h -> h_addr_list [i], (unsigned)(h -> h_length)); | |
6c6d5928 | 547 | } |
65bf41da | 548 | #ifdef DEBUG_EVAL |
8ae2d595 | 549 | log_debug ("dns -> data: %x h -> h_addr_list [0]: %x", |
b1b7b521 | 550 | *(int *)(dns -> buffer), h -> h_addr_list [0]); |
65bf41da | 551 | #endif |
d7837182 | 552 | |
1d07a807 | 553 | /* XXX Set the timeout for an hour from now. |
d7837182 TL |
554 | XXX This should really use the time on the DNS reply. */ |
555 | dns -> timeout = cur_time + 3600; | |
556 | ||
65bf41da | 557 | #ifdef DEBUG_EVAL |
8ae2d595 | 558 | log_debug ("hard copy: %d %s", dns -> data.len, |
1d07a807 TL |
559 | (dns -> data.len > 4 |
560 | ? inet_ntoa (*(struct in_addr *)(dns -> data.data)) : 0)); | |
65bf41da | 561 | #endif |
4cbc378f | 562 | data_string_copy (result, &dns -> data, MDL); |
1d07a807 | 563 | return 1; |
d7837182 TL |
564 | } |
565 | ||
16121af5 | 566 | int evaluate_expression (result, packet, lease, client_state, |
d758ad8c | 567 | in_options, cfg_options, scope, expr, file, line) |
9f7050df TL |
568 | struct binding_value **result; |
569 | struct packet *packet; | |
570 | struct lease *lease; | |
16121af5 | 571 | struct client_state *client_state; |
9f7050df TL |
572 | struct option_state *in_options; |
573 | struct option_state *cfg_options; | |
6ceb9118 | 574 | struct binding_scope **scope; |
9f7050df | 575 | struct expression *expr; |
d758ad8c TL |
576 | const char *file; |
577 | int line; | |
9f7050df TL |
578 | { |
579 | struct binding_value *bv; | |
580 | int status; | |
581 | struct binding *binding; | |
582 | ||
583 | bv = (struct binding_value *)0; | |
584 | ||
585 | if (expr -> op == expr_variable_reference) { | |
6ceb9118 TL |
586 | if (!scope || !*scope) |
587 | return 0; | |
588 | ||
589 | binding = find_binding (*scope, expr -> data.variable); | |
9f7050df TL |
590 | |
591 | if (binding && binding -> value) { | |
592 | if (result) | |
593 | binding_value_reference (result, | |
594 | binding -> value, | |
d758ad8c | 595 | file, line); |
9f7050df TL |
596 | return 1; |
597 | } else | |
598 | return 0; | |
599 | } else if (expr -> op == expr_funcall) { | |
600 | struct string_list *s; | |
601 | struct expression *arg; | |
602 | struct binding_scope *ns; | |
603 | struct binding *nb; | |
6ceb9118 TL |
604 | |
605 | if (!scope || !*scope) { | |
606 | log_error ("%s: no such function.", | |
607 | expr -> data.funcall.name); | |
608 | return 0; | |
609 | } | |
610 | ||
611 | binding = find_binding (*scope, expr -> data.funcall.name); | |
9f7050df TL |
612 | |
613 | if (!binding || !binding -> value) { | |
614 | log_error ("%s: no such function.", | |
615 | expr -> data.funcall.name); | |
616 | return 0; | |
617 | } | |
618 | if (binding -> value -> type != binding_function) { | |
619 | log_error ("%s: not a function.", | |
620 | expr -> data.funcall.name); | |
621 | return 0; | |
622 | } | |
623 | ||
624 | /* Create a new binding scope in which to define | |
625 | the arguments to the function. */ | |
626 | ns = (struct binding_scope *)0; | |
627 | if (!binding_scope_allocate (&ns, MDL)) { | |
628 | log_error ("%s: can't allocate argument scope.", | |
629 | expr -> data.funcall.name); | |
630 | return 0; | |
631 | } | |
632 | ||
633 | arg = expr -> data.funcall.arglist; | |
800f0de7 | 634 | s = binding -> value -> value.fundef -> args; |
9f7050df TL |
635 | while (arg && s) { |
636 | nb = dmalloc (sizeof *nb, MDL); | |
637 | if (!nb) { | |
638 | blb: | |
639 | binding_scope_dereference (&ns, MDL); | |
640 | return 0; | |
641 | } else { | |
55321a21 | 642 | memset (nb, 0, sizeof *nb); |
9f7050df TL |
643 | nb -> name = dmalloc (strlen (s -> string) + 1, |
644 | MDL); | |
645 | if (nb -> name) | |
55321a21 | 646 | strcpy (nb -> name, s -> string); |
9f7050df TL |
647 | else { |
648 | dfree (nb, MDL); | |
649 | nb = (struct binding *)0; | |
650 | goto blb; | |
651 | } | |
652 | } | |
653 | evaluate_expression (&nb -> value, packet, lease, | |
16121af5 | 654 | client_state, |
9f7050df | 655 | in_options, cfg_options, scope, |
d758ad8c | 656 | arg -> data.arg.val, file, line); |
9f7050df TL |
657 | nb -> next = ns -> bindings; |
658 | ns -> bindings = nb; | |
659 | arg = arg -> data.arg.next; | |
660 | s = s -> next; | |
661 | } | |
662 | if (arg) { | |
663 | log_error ("%s: too many arguments.", | |
664 | expr -> data.funcall.name); | |
665 | binding_scope_dereference (&ns, MDL); | |
666 | return 0; | |
667 | } | |
668 | if (s) { | |
669 | log_error ("%s: too few arguments.", | |
670 | expr -> data.funcall.name); | |
671 | binding_scope_dereference (&ns, MDL); | |
672 | return 0; | |
673 | } | |
674 | ||
6ceb9118 TL |
675 | if (scope && *scope) |
676 | binding_scope_reference (&ns -> outer, *scope, MDL); | |
677 | ||
1b234d44 | 678 | status = (execute_statements |
16121af5 TL |
679 | (&bv, packet, |
680 | lease, client_state, in_options, cfg_options, &ns, | |
1b234d44 | 681 | binding -> value -> value.fundef -> statements)); |
9f7050df | 682 | binding_scope_dereference (&ns, MDL); |
1b234d44 DN |
683 | |
684 | if (!bv) | |
685 | return 1; | |
9f7050df TL |
686 | } else if (is_boolean_expression (expr)) { |
687 | if (!binding_value_allocate (&bv, MDL)) | |
688 | return 0; | |
689 | bv -> type = binding_boolean; | |
690 | status = (evaluate_boolean_expression | |
16121af5 TL |
691 | (&bv -> value.boolean, packet, lease, client_state, |
692 | in_options, cfg_options, scope, expr)); | |
9f7050df TL |
693 | } else if (is_numeric_expression (expr)) { |
694 | if (!binding_value_allocate (&bv, MDL)) | |
695 | return 0; | |
696 | bv -> type = binding_numeric; | |
697 | status = (evaluate_numeric_expression | |
16121af5 TL |
698 | (&bv -> value.intval, packet, lease, client_state, |
699 | in_options, cfg_options, scope, expr)); | |
9f7050df TL |
700 | } else if (is_data_expression (expr)) { |
701 | if (!binding_value_allocate (&bv, MDL)) | |
702 | return 0; | |
703 | bv -> type = binding_data; | |
704 | status = (evaluate_data_expression | |
16121af5 | 705 | (&bv -> value.data, packet, lease, client_state, |
d758ad8c | 706 | in_options, cfg_options, scope, expr, MDL)); |
9f7050df TL |
707 | } else if (is_dns_expression (expr)) { |
708 | #if defined (NSUPDATE) | |
709 | if (!binding_value_allocate (&bv, MDL)) | |
710 | return 0; | |
711 | bv -> type = binding_dns; | |
712 | status = (evaluate_dns_expression | |
16121af5 TL |
713 | (&bv -> value.dns, packet, lease, client_state, |
714 | in_options, cfg_options, scope, expr)); | |
9f7050df TL |
715 | #endif |
716 | } else { | |
717 | log_error ("%s: invalid expression type: %d", | |
718 | "evaluate_expression", expr -> op); | |
1b234d44 | 719 | return 0; |
9f7050df | 720 | } |
16121af5 | 721 | if (result && status) |
d758ad8c | 722 | binding_value_reference (result, bv, file, line); |
9f7050df TL |
723 | binding_value_dereference (&bv, MDL); |
724 | ||
725 | return status; | |
726 | } | |
727 | ||
728 | int binding_value_dereference (struct binding_value **v, | |
729 | const char *file, int line) | |
730 | { | |
731 | struct binding_value *bv = *v; | |
732 | ||
733 | *v = (struct binding_value *)0; | |
734 | ||
735 | /* Decrement the reference count. If it's nonzero, we're | |
736 | done. */ | |
737 | --(bv -> refcnt); | |
98311e4b | 738 | rc_register (file, line, v, bv, bv -> refcnt, 1, RC_MISC); |
9f7050df TL |
739 | if (bv -> refcnt > 0) |
740 | return 1; | |
741 | if (bv -> refcnt < 0) { | |
742 | log_error ("%s(%d): negative refcnt!", file, line); | |
743 | #if defined (DEBUG_RC_HISTORY) | |
d758ad8c | 744 | dump_rc_history (bv); |
9f7050df TL |
745 | #endif |
746 | #if defined (POINTER_DEBUG) | |
747 | abort (); | |
748 | #else | |
749 | return 0; | |
750 | #endif | |
751 | } | |
752 | ||
753 | switch (bv -> type) { | |
754 | case binding_boolean: | |
755 | case binding_numeric: | |
756 | break; | |
757 | case binding_data: | |
758 | if (bv -> value.data.buffer) | |
759 | data_string_forget (&bv -> value.data, file, line); | |
760 | break; | |
761 | case binding_dns: | |
762 | #if defined (NSUPDATE) | |
763 | if (bv -> value.dns) { | |
764 | if (bv -> value.dns -> r_data) { | |
79c36eb7 | 765 | dfree (bv -> value.dns -> r_data_ephem, MDL); |
9f7050df | 766 | bv -> value.dns -> r_data = (unsigned char *)0; |
79c36eb7 TL |
767 | bv -> value.dns -> r_data_ephem = |
768 | (unsigned char *)0; | |
9f7050df TL |
769 | } |
770 | minires_freeupdrec (bv -> value.dns); | |
771 | } | |
772 | break; | |
773 | #endif | |
774 | default: | |
775 | log_error ("%s(%d): invalid binding type: %d", | |
776 | file, line, bv -> type); | |
777 | return 0; | |
778 | } | |
fd792685 | 779 | free_binding_value(bv, file, line); |
9f7050df TL |
780 | return 1; |
781 | } | |
782 | ||
4bd8800e | 783 | #if defined (NSUPDATE) |
16121af5 | 784 | int evaluate_dns_expression (result, packet, lease, client_state, in_options, |
4cbc378f | 785 | cfg_options, scope, expr) |
4bae15ec TL |
786 | ns_updrec **result; |
787 | struct packet *packet; | |
788 | struct lease *lease; | |
16121af5 | 789 | struct client_state *client_state; |
4bae15ec TL |
790 | struct option_state *in_options; |
791 | struct option_state *cfg_options; | |
6ceb9118 | 792 | struct binding_scope **scope; |
4bae15ec TL |
793 | struct expression *expr; |
794 | { | |
795 | ns_updrec *foo; | |
796 | unsigned long ttl = 0; | |
797 | char *tname; | |
798 | struct data_string name, data; | |
799 | int r0, r1, r2, r3; | |
800 | ||
801 | if (!result || *result) { | |
802 | log_error ("evaluate_dns_expression called with non-null %s", | |
803 | "result pointer"); | |
804 | #if defined (POINTER_DEBUG) | |
805 | abort (); | |
806 | #else | |
807 | return 0; | |
808 | #endif | |
809 | } | |
810 | ||
811 | switch (expr -> op) { | |
812 | #if defined (NSUPDATE) | |
2e236508 | 813 | case expr_ns_add: |
4bae15ec | 814 | r0 = evaluate_numeric_expression (&ttl, packet, lease, |
16121af5 | 815 | client_state, |
4bae15ec | 816 | in_options, cfg_options, |
4cbc378f | 817 | scope, |
2e236508 | 818 | expr -> data.ns_add.ttl); |
4bae15ec TL |
819 | goto nsfinish; |
820 | ||
821 | case expr_ns_exists: | |
822 | ttl = 1; | |
823 | ||
824 | case expr_ns_delete: | |
825 | case expr_ns_not_exists: | |
826 | r0 = 1; | |
827 | nsfinish: | |
2e236508 | 828 | memset (&name, 0, sizeof name); |
4bae15ec | 829 | r1 = evaluate_data_expression (&name, packet, lease, |
16121af5 | 830 | client_state, |
4cbc378f | 831 | in_options, cfg_options, scope, |
d758ad8c TL |
832 | expr -> data.ns_add.rrname, |
833 | MDL); | |
4bae15ec TL |
834 | if (r1) { |
835 | /* The result of the evaluation may or may not | |
836 | be NUL-terminated, but we need it | |
837 | terminated for sure, so we have to allocate | |
838 | a buffer and terminate it. */ | |
4cbc378f | 839 | tname = dmalloc (name.len + 1, MDL); |
4bae15ec TL |
840 | if (!tname) { |
841 | r2 = 0; | |
842 | r1 = 0; | |
4cbc378f | 843 | data_string_forget (&name, MDL); |
4bae15ec TL |
844 | } else { |
845 | memcpy (tname, name.data, name.len); | |
846 | tname [name.len] = 0; | |
2e236508 | 847 | memset (&data, 0, sizeof data); |
4bae15ec | 848 | r2 = evaluate_data_expression |
16121af5 TL |
849 | (&data, packet, lease, client_state, |
850 | in_options, cfg_options, scope, | |
d758ad8c | 851 | expr -> data.ns_add.rrdata, MDL); |
4bae15ec | 852 | } |
98311e4b | 853 | } else { |
4bae15ec | 854 | r2 = 0; |
98311e4b DH |
855 | tname = NULL; |
856 | } | |
2e236508 | 857 | if (r0 && r1 && (r2 || expr -> op != expr_ns_add)) { |
88c32c8c TL |
858 | *result = minires_mkupdrec (((expr -> op == expr_ns_add || |
859 | expr -> op == expr_ns_delete) | |
860 | ? S_UPDATE : S_PREREQ), | |
861 | tname, | |
862 | expr -> data.ns_add.rrclass, | |
863 | expr -> data.ns_add.rrtype, | |
864 | ttl); | |
4bae15ec TL |
865 | if (!*result) { |
866 | ngood: | |
867 | if (r2) { | |
4cbc378f | 868 | data_string_forget (&data, MDL); |
4bae15ec TL |
869 | r2 = 0; |
870 | } | |
871 | } else { | |
872 | if (data.len) { | |
2e236508 TL |
873 | /* As a special case, if we get exactly |
874 | four bytes of data, it's an IP address | |
875 | represented as a 32-bit quantity, which | |
876 | is actually what we *should* be getting | |
877 | here. Because res_mkupdrec is currently | |
878 | broken and expects a dotted quad, convert | |
879 | it. This should be fixed when the new | |
880 | resolver is merged. */ | |
881 | if (data.len == 4) { | |
79c36eb7 TL |
882 | (*result) -> r_data_ephem = |
883 | dmalloc (16, MDL); | |
884 | if (!(*result) -> r_data_ephem) | |
2e236508 | 885 | goto dpngood; |
79c36eb7 TL |
886 | (*result) -> r_data = |
887 | (*result) -> r_data_ephem; | |
98311e4b | 888 | /*%Audit% 16 bytes max. %2004.06.17,Safe%*/ |
79c36eb7 | 889 | sprintf ((char *)(*result) -> r_data_ephem, |
98311e4b DH |
890 | "%u.%u.%u.%u", |
891 | data.data [0] & 0xff, | |
892 | data.data [1] & 0xff, | |
893 | data.data [2] & 0xff, | |
894 | data.data [3] & 0xff); | |
2e236508 | 895 | (*result) -> r_size = |
79c36eb7 | 896 | strlen ((const char *) |
9458e9aa | 897 | (*result) -> r_data); |
2e236508 TL |
898 | } else { |
899 | (*result) -> r_size = data.len; | |
79c36eb7 TL |
900 | (*result) -> r_data_ephem = |
901 | dmalloc (data.len, MDL); | |
902 | if (!(*result) -> r_data_ephem) { | |
2e236508 | 903 | dpngood: /* double plus ungood. */ |
88c32c8c | 904 | minires_freeupdrec (*result); |
4bae15ec TL |
905 | *result = 0; |
906 | goto ngood; | |
2e236508 | 907 | } |
79c36eb7 TL |
908 | (*result) -> r_data = |
909 | (*result) -> r_data_ephem; | |
910 | memcpy ((*result) -> r_data_ephem, | |
2e236508 | 911 | data.data, data.len); |
4bae15ec | 912 | } |
4bae15ec TL |
913 | } else { |
914 | (*result) -> r_data = 0; | |
915 | (*result) -> r_size = 0; | |
916 | } | |
917 | switch (expr -> op) { | |
2e236508 | 918 | case expr_ns_add: |
4bae15ec TL |
919 | (*result) -> r_opcode = ADD; |
920 | break; | |
921 | case expr_ns_delete: | |
922 | (*result) -> r_opcode = DELETE; | |
923 | break; | |
924 | case expr_ns_exists: | |
925 | (*result) -> r_opcode = YXRRSET; | |
926 | break; | |
927 | case expr_ns_not_exists: | |
928 | (*result) -> r_opcode = NXRRSET; | |
929 | break; | |
930 | ||
931 | /* Can't happen, but satisfy gcc. */ | |
932 | default: | |
933 | break; | |
934 | } | |
935 | } | |
936 | } | |
937 | if (r1) { | |
4cbc378f TL |
938 | data_string_forget (&name, MDL); |
939 | dfree (tname, MDL); | |
4bae15ec TL |
940 | } |
941 | if (r2) | |
4cbc378f | 942 | data_string_forget (&data, MDL); |
4bae15ec TL |
943 | /* One flaw in the thinking here: an IP address and an |
944 | ASCII string both look like data expressions, but | |
945 | for A records, we want an ASCII string, not a | |
946 | binary IP address. Do I need to turn binary IP | |
c57db45c | 947 | addresses into a separate type? */ |
4cbc378f TL |
948 | return (r0 && r1 && |
949 | (r2 || expr -> op != expr_ns_add) && *result); | |
4bae15ec TL |
950 | |
951 | #else | |
2e236508 | 952 | case expr_ns_add: |
4bae15ec TL |
953 | case expr_ns_delete: |
954 | case expr_ns_exists: | |
955 | case expr_ns_not_exists: | |
956 | return 0; | |
957 | #endif | |
9f7050df TL |
958 | case expr_funcall: |
959 | log_error ("%s: dns values for functions not supported.", | |
960 | expr -> data.funcall.name); | |
961 | break; | |
962 | ||
963 | case expr_variable_reference: | |
964 | log_error ("%s: dns values for variables not supported.", | |
965 | expr -> data.variable); | |
966 | break; | |
967 | ||
4bae15ec TL |
968 | case expr_check: |
969 | case expr_equal: | |
970 | case expr_not_equal: | |
971 | case expr_and: | |
972 | case expr_or: | |
973 | case expr_not: | |
974 | case expr_match: | |
975 | case expr_static: | |
976 | case expr_known: | |
977 | case expr_exists: | |
2e236508 TL |
978 | case expr_variable_exists: |
979 | log_error ("Boolean opcode in evaluate_dns_expression: %d", | |
4bae15ec TL |
980 | expr -> op); |
981 | return 0; | |
982 | ||
983 | case expr_none: | |
984 | case expr_substring: | |
985 | case expr_suffix: | |
2727c1cf DH |
986 | case expr_lcase: |
987 | case expr_ucase: | |
4bae15ec TL |
988 | case expr_option: |
989 | case expr_hardware: | |
990 | case expr_const_data: | |
991 | case expr_packet: | |
992 | case expr_concat: | |
993 | case expr_encapsulate: | |
994 | case expr_host_lookup: | |
995 | case expr_encode_int8: | |
996 | case expr_encode_int16: | |
997 | case expr_encode_int32: | |
998 | case expr_binary_to_ascii: | |
999 | case expr_reverse: | |
4cbc378f TL |
1000 | case expr_filename: |
1001 | case expr_sname: | |
4bae15ec TL |
1002 | case expr_pick_first_value: |
1003 | case expr_host_decl_name: | |
1004 | case expr_config_option: | |
1005 | case expr_leased_address: | |
2e236508 | 1006 | case expr_null: |
2e236508 | 1007 | log_error ("Data opcode in evaluate_dns_expression: %d", |
4bae15ec TL |
1008 | expr -> op); |
1009 | return 0; | |
1010 | ||
1011 | case expr_extract_int8: | |
1012 | case expr_extract_int16: | |
1013 | case expr_extract_int32: | |
1014 | case expr_const_int: | |
1015 | case expr_lease_time: | |
2e236508 | 1016 | case expr_dns_transaction: |
800f0de7 TL |
1017 | case expr_add: |
1018 | case expr_subtract: | |
1019 | case expr_multiply: | |
1020 | case expr_divide: | |
1021 | case expr_remainder: | |
3c98e80b DN |
1022 | case expr_binary_and: |
1023 | case expr_binary_or: | |
1024 | case expr_binary_xor: | |
16121af5 | 1025 | case expr_client_state: |
2e236508 | 1026 | log_error ("Numeric opcode in evaluate_dns_expression: %d", |
4bae15ec TL |
1027 | expr -> op); |
1028 | return 0; | |
9f7050df | 1029 | |
7d9784f6 TL |
1030 | case expr_function: |
1031 | log_error ("Function opcode in evaluate_dns_expression: %d", | |
1032 | expr -> op); | |
1033 | return 0; | |
1034 | ||
9f7050df TL |
1035 | case expr_arg: |
1036 | break; | |
4bae15ec TL |
1037 | } |
1038 | ||
1039 | log_error ("Bogus opcode in evaluate_dns_expression: %d", | |
1040 | expr -> op); | |
1041 | return 0; | |
1042 | } | |
4bd8800e | 1043 | #endif /* defined (NSUPDATE) */ |
4bae15ec | 1044 | |
16121af5 TL |
1045 | int evaluate_boolean_expression (result, packet, lease, client_state, |
1046 | in_options, cfg_options, scope, expr) | |
1d07a807 | 1047 | int *result; |
33e712ea | 1048 | struct packet *packet; |
da38df14 | 1049 | struct lease *lease; |
16121af5 | 1050 | struct client_state *client_state; |
4038ec52 TL |
1051 | struct option_state *in_options; |
1052 | struct option_state *cfg_options; | |
6ceb9118 | 1053 | struct binding_scope **scope; |
33e712ea | 1054 | struct expression *expr; |
d7837182 | 1055 | { |
33e712ea | 1056 | struct data_string left, right; |
d9eefc5d | 1057 | struct data_string rrtype, rrname, rrdata; |
0acdc228 | 1058 | unsigned long ttl; |
d9eefc5d | 1059 | int srrtype, srrname, srrdata, sttl; |
1d07a807 TL |
1060 | int bleft, bright; |
1061 | int sleft, sright; | |
2e236508 | 1062 | struct binding *binding; |
2c46528f | 1063 | struct binding_value *bv, *obv; |
33e712ea TL |
1064 | |
1065 | switch (expr -> op) { | |
1066 | case expr_check: | |
da38df14 TL |
1067 | *result = check_collection (packet, lease, |
1068 | expr -> data.check); | |
78310bee | 1069 | #if defined (DEBUG_EXPRESSIONS) |
27b3a58f | 1070 | log_debug ("bool: check (%s) returns %s", |
2c46528f TL |
1071 | expr -> data.check -> name, |
1072 | *result ? "true" : "false"); | |
1d07a807 TL |
1073 | #endif |
1074 | return 1; | |
33e712ea TL |
1075 | |
1076 | case expr_equal: | |
2b965a44 | 1077 | case expr_not_equal: |
2c46528f TL |
1078 | bv = obv = (struct binding_value *)0; |
1079 | sleft = evaluate_expression (&bv, packet, lease, client_state, | |
1080 | in_options, cfg_options, scope, | |
d758ad8c | 1081 | expr -> data.equal [0], MDL); |
2c46528f TL |
1082 | sright = evaluate_expression (&obv, packet, lease, |
1083 | client_state, in_options, | |
1084 | cfg_options, scope, | |
d758ad8c | 1085 | expr -> data.equal [1], MDL); |
1d07a807 | 1086 | if (sleft && sright) { |
2c46528f TL |
1087 | if (bv -> type != obv -> type) |
1088 | *result = expr -> op == expr_not_equal; | |
1089 | else { | |
1090 | switch (obv -> type) { | |
1091 | case binding_boolean: | |
1092 | if (bv -> value.boolean == obv -> value.boolean) | |
2b965a44 | 1093 | *result = expr -> op == expr_equal; |
2c46528f TL |
1094 | else |
1095 | *result = expr -> op == expr_not_equal; | |
1096 | break; | |
1097 | ||
1098 | case binding_data: | |
1099 | if ((bv -> value.data.len == | |
1100 | obv -> value.data.len) && | |
1101 | !memcmp (bv -> value.data.data, | |
1102 | obv -> value.data.data, | |
1103 | obv -> value.data.len)) | |
1104 | *result = expr -> op == expr_equal; | |
1105 | else | |
1106 | *result = expr -> op == expr_not_equal; | |
1107 | break; | |
1108 | ||
1109 | case binding_numeric: | |
1110 | if (bv -> value.intval == obv -> value.intval) | |
1111 | *result = expr -> op == expr_equal; | |
1112 | else | |
2b965a44 | 1113 | *result = expr -> op == expr_not_equal; |
2c46528f TL |
1114 | break; |
1115 | ||
1116 | case binding_dns: | |
6cff8371 | 1117 | #if defined (NSUPDATE) |
2c46528f TL |
1118 | /* XXX This should be a comparison for equal |
1119 | XXX values, not for identity. */ | |
1120 | if (bv -> value.dns == obv -> value.dns) | |
1121 | *result = expr -> op == expr_equal; | |
1122 | else | |
1123 | *result = expr -> op == expr_not_equal; | |
6cff8371 TL |
1124 | #else |
1125 | *result = expr -> op == expr_not_equal; | |
1126 | #endif | |
2c46528f TL |
1127 | break; |
1128 | ||
1129 | case binding_function: | |
1130 | if (bv -> value.fundef == obv -> value.fundef) | |
1131 | *result = expr -> op == expr_equal; | |
1132 | else | |
1133 | *result = expr -> op == expr_not_equal; | |
1134 | break; | |
1135 | default: | |
1136 | *result = expr -> op == expr_not_equal; | |
1137 | break; | |
1138 | } | |
1139 | } | |
16121af5 | 1140 | } else if (!sleft && !sright) |
2c46528f | 1141 | *result = expr -> op == expr_equal; |
16121af5 | 1142 | else |
2c46528f | 1143 | *result = expr -> op == expr_not_equal; |
1d07a807 TL |
1144 | |
1145 | #if defined (DEBUG_EXPRESSIONS) | |
2c46528f | 1146 | log_debug ("bool: %sequal = %s", |
2b965a44 | 1147 | expr -> op == expr_not_equal ? "not" : "", |
16121af5 | 1148 | (*result ? "true" : "false")); |
1d07a807 TL |
1149 | #endif |
1150 | if (sleft) | |
2c46528f | 1151 | binding_value_dereference (&bv, MDL); |
1d07a807 | 1152 | if (sright) |
2c46528f | 1153 | binding_value_dereference (&obv, MDL); |
16121af5 | 1154 | return 1; |
33e712ea TL |
1155 | |
1156 | case expr_and: | |
4038ec52 | 1157 | sleft = evaluate_boolean_expression (&bleft, packet, lease, |
16121af5 | 1158 | client_state, |
4038ec52 | 1159 | in_options, cfg_options, |
4cbc378f | 1160 | scope, |
1d07a807 | 1161 | expr -> data.and [0]); |
0e97ecc8 TL |
1162 | if (sleft && bleft) |
1163 | sright = evaluate_boolean_expression | |
16121af5 | 1164 | (&bright, packet, lease, client_state, |
0e97ecc8 TL |
1165 | in_options, cfg_options, |
1166 | scope, expr -> data.and [1]); | |
1167 | else | |
1168 | sright = bright = 0; | |
1d07a807 TL |
1169 | |
1170 | #if defined (DEBUG_EXPRESSIONS) | |
27b3a58f | 1171 | log_debug ("bool: and (%s, %s) = %s", |
1d07a807 TL |
1172 | sleft ? (bleft ? "true" : "false") : "NULL", |
1173 | sright ? (bright ? "true" : "false") : "NULL", | |
1174 | ((sleft && sright) | |
1175 | ? (bleft && bright ? "true" : "false") : "NULL")); | |
1176 | #endif | |
1177 | if (sleft && sright) { | |
1178 | *result = bleft && bright; | |
1179 | return 1; | |
1180 | } | |
1181 | return 0; | |
33e712ea TL |
1182 | |
1183 | case expr_or: | |
2541d057 | 1184 | bleft = bright = 0; |
4038ec52 | 1185 | sleft = evaluate_boolean_expression (&bleft, packet, lease, |
16121af5 | 1186 | client_state, |
4038ec52 | 1187 | in_options, cfg_options, |
4cbc378f | 1188 | scope, |
1d07a807 | 1189 | expr -> data.or [0]); |
2541d057 | 1190 | if (!sleft || !bleft) |
0e97ecc8 | 1191 | sright = evaluate_boolean_expression |
16121af5 | 1192 | (&bright, packet, lease, client_state, |
0e97ecc8 TL |
1193 | in_options, cfg_options, |
1194 | scope, expr -> data.or [1]); | |
1195 | else | |
2541d057 | 1196 | sright = 0; |
1d07a807 | 1197 | #if defined (DEBUG_EXPRESSIONS) |
27b3a58f | 1198 | log_debug ("bool: or (%s, %s) = %s", |
1d07a807 TL |
1199 | sleft ? (bleft ? "true" : "false") : "NULL", |
1200 | sright ? (bright ? "true" : "false") : "NULL", | |
2541d057 | 1201 | ((sleft || sright) |
1d07a807 TL |
1202 | ? (bleft || bright ? "true" : "false") : "NULL")); |
1203 | #endif | |
2541d057 | 1204 | if (sleft || sright) { |
1d07a807 TL |
1205 | *result = bleft || bright; |
1206 | return 1; | |
1207 | } | |
1208 | return 0; | |
33e712ea TL |
1209 | |
1210 | case expr_not: | |
4038ec52 | 1211 | sleft = evaluate_boolean_expression (&bleft, packet, lease, |
16121af5 | 1212 | client_state, |
4038ec52 | 1213 | in_options, cfg_options, |
4cbc378f | 1214 | scope, |
1d07a807 TL |
1215 | expr -> data.not); |
1216 | #if defined (DEBUG_EXPRESSIONS) | |
27b3a58f | 1217 | log_debug ("bool: not (%s) = %s", |
1d07a807 TL |
1218 | sleft ? (bleft ? "true" : "false") : "NULL", |
1219 | ((sleft && sright) | |
1220 | ? (!bleft ? "true" : "false") : "NULL")); | |
1221 | ||
1222 | #endif | |
1223 | if (sleft) { | |
1224 | *result = !bleft; | |
1225 | return 1; | |
1226 | } | |
1227 | return 0; | |
1228 | ||
1229 | case expr_exists: | |
1230 | memset (&left, 0, sizeof left); | |
4038ec52 | 1231 | if (!in_options || |
975bd464 | 1232 | !get_option (&left, expr -> data.exists -> universe, |
16121af5 TL |
1233 | packet, lease, client_state, |
1234 | in_options, cfg_options, in_options, | |
d758ad8c | 1235 | scope, expr -> data.exists -> code, MDL)) |
1d07a807 TL |
1236 | *result = 0; |
1237 | else { | |
1238 | *result = 1; | |
4cbc378f | 1239 | data_string_forget (&left, MDL); |
1d07a807 TL |
1240 | } |
1241 | #if defined (DEBUG_EXPRESSIONS) | |
27b3a58f | 1242 | log_debug ("bool: exists %s.%s = %s", |
4cbc378f TL |
1243 | expr -> data.option -> universe -> name, |
1244 | expr -> data.option -> name, | |
16121af5 | 1245 | *result ? "true" : "false"); |
1d07a807 TL |
1246 | #endif |
1247 | return 1; | |
33e712ea | 1248 | |
5ce6b576 TL |
1249 | case expr_known: |
1250 | if (!packet) { | |
1251 | #if defined (DEBUG_EXPRESSIONS) | |
27b3a58f | 1252 | log_debug ("bool: known = NULL"); |
5ce6b576 TL |
1253 | #endif |
1254 | return 0; | |
1255 | } | |
1256 | #if defined (DEBUG_EXPRESSIONS) | |
27b3a58f | 1257 | log_debug ("bool: known = %s", |
5ce6b576 TL |
1258 | packet -> known ? "true" : "false"); |
1259 | #endif | |
1260 | *result = packet -> known; | |
1261 | return 1; | |
1262 | ||
1c5d5731 TL |
1263 | case expr_static: |
1264 | if (!lease || !(lease -> flags & STATIC_LEASE)) { | |
1265 | #if defined (DEBUG_EXPRESSIONS) | |
aab30e3b TL |
1266 | log_debug ("bool: static = false (%s %s %s %d)", |
1267 | lease ? "y" : "n", | |
1268 | (lease && (lease -> flags & STATIC_LEASE) | |
1269 | ? "y" : "n"), | |
1270 | piaddr (lease -> ip_addr), | |
1271 | lease ? lease -> flags : 0); | |
1c5d5731 TL |
1272 | #endif |
1273 | *result = 0; | |
1274 | return 1; | |
1275 | } | |
1276 | #if defined (DEBUG_EXPRESSIONS) | |
1277 | log_debug ("bool: static = true"); | |
1278 | #endif | |
1279 | *result = 1; | |
1280 | return 1; | |
1281 | ||
2e236508 | 1282 | case expr_variable_exists: |
6ceb9118 TL |
1283 | if (scope && *scope) { |
1284 | binding = find_binding (*scope, expr -> data.variable); | |
4cbc378f | 1285 | |
6ceb9118 TL |
1286 | if (binding) { |
1287 | if (binding -> value) | |
1288 | *result = 1; | |
1289 | else | |
1290 | *result = 0; | |
1291 | } else | |
2e236508 TL |
1292 | *result = 0; |
1293 | } else | |
1294 | *result = 0; | |
1295 | #if defined (DEBUG_EXPRESSIONS) | |
0e97ecc8 | 1296 | log_debug ("boolean: %s? = %s", expr -> data.variable, |
16121af5 | 1297 | *result ? "true" : "false"); |
2e236508 TL |
1298 | #endif |
1299 | return 1; | |
1300 | ||
9f7050df | 1301 | case expr_variable_reference: |
6ceb9118 TL |
1302 | if (scope && *scope) { |
1303 | binding = find_binding (*scope, expr -> data.variable); | |
9f7050df | 1304 | |
6ceb9118 TL |
1305 | if (binding && binding -> value) { |
1306 | if (binding -> value -> type == | |
1307 | binding_boolean) { | |
9f7050df | 1308 | *result = binding -> value -> value.boolean; |
6ceb9118 | 1309 | sleft = 1; |
9f7050df TL |
1310 | } else { |
1311 | log_error ("binding type %d in %s.", | |
1312 | binding -> value -> type, | |
1313 | "evaluate_boolean_expression"); | |
1314 | sleft = 0; | |
1315 | } | |
6ceb9118 TL |
1316 | } else |
1317 | sleft = 0; | |
9f7050df TL |
1318 | } else |
1319 | sleft = 0; | |
1320 | #if defined (DEBUG_EXPRESSIONS) | |
0e97ecc8 | 1321 | log_debug ("boolean: %s = %s", expr -> data.variable, |
9f7050df TL |
1322 | sleft ? (*result ? "true" : "false") : "NULL"); |
1323 | #endif | |
1324 | return sleft; | |
1325 | ||
1326 | case expr_funcall: | |
1327 | bv = (struct binding_value *)0; | |
16121af5 | 1328 | sleft = evaluate_expression (&bv, packet, lease, client_state, |
9f7050df | 1329 | in_options, cfg_options, |
d758ad8c | 1330 | scope, expr, MDL); |
9f7050df TL |
1331 | if (sleft) { |
1332 | if (bv -> type != binding_boolean) | |
1333 | log_error ("%s() returned type %d in %s.", | |
1334 | expr -> data.funcall.name, | |
1335 | bv -> type, | |
1336 | "evaluate_boolean_expression"); | |
1337 | else | |
1338 | *result = bv -> value.boolean; | |
1339 | binding_value_dereference (&bv, MDL); | |
1340 | } | |
1341 | #if defined (DEBUG_EXPRESSIONS) | |
1342 | log_debug ("boolean: %s() = %s", expr -> data.funcall.name, | |
1343 | sleft ? (*result ? "true" : "false") : "NULL"); | |
1344 | #endif | |
1345 | break; | |
1346 | ||
b1b7b521 TL |
1347 | case expr_none: |
1348 | case expr_match: | |
33e712ea TL |
1349 | case expr_substring: |
1350 | case expr_suffix: | |
2727c1cf DH |
1351 | case expr_lcase: |
1352 | case expr_ucase: | |
33e712ea TL |
1353 | case expr_option: |
1354 | case expr_hardware: | |
1355 | case expr_const_data: | |
1356 | case expr_packet: | |
1357 | case expr_concat: | |
dd6e44a5 | 1358 | case expr_encapsulate: |
33e712ea | 1359 | case expr_host_lookup: |
20a767d3 TL |
1360 | case expr_encode_int8: |
1361 | case expr_encode_int16: | |
1362 | case expr_encode_int32: | |
da38df14 TL |
1363 | case expr_binary_to_ascii: |
1364 | case expr_reverse: | |
79a65726 TL |
1365 | case expr_pick_first_value: |
1366 | case expr_host_decl_name: | |
1367 | case expr_config_option: | |
da38df14 | 1368 | case expr_leased_address: |
2e236508 | 1369 | case expr_null: |
4bd8800e TL |
1370 | case expr_filename: |
1371 | case expr_sname: | |
8ae2d595 | 1372 | log_error ("Data opcode in evaluate_boolean_expression: %d", |
33e712ea TL |
1373 | expr -> op); |
1374 | return 0; | |
d7837182 | 1375 | |
33e712ea TL |
1376 | case expr_extract_int8: |
1377 | case expr_extract_int16: | |
1378 | case expr_extract_int32: | |
1379 | case expr_const_int: | |
cd31814f | 1380 | case expr_lease_time: |
4bae15ec | 1381 | case expr_dns_transaction: |
800f0de7 TL |
1382 | case expr_add: |
1383 | case expr_subtract: | |
1384 | case expr_multiply: | |
1385 | case expr_divide: | |
1386 | case expr_remainder: | |
3c98e80b DN |
1387 | case expr_binary_and: |
1388 | case expr_binary_or: | |
1389 | case expr_binary_xor: | |
16121af5 | 1390 | case expr_client_state: |
8ae2d595 | 1391 | log_error ("Numeric opcode in evaluate_boolean_expression: %d", |
33e712ea TL |
1392 | expr -> op); |
1393 | return 0; | |
4bae15ec | 1394 | |
2e236508 | 1395 | case expr_ns_add: |
4bae15ec TL |
1396 | case expr_ns_delete: |
1397 | case expr_ns_exists: | |
1398 | case expr_ns_not_exists: | |
1399 | log_error ("dns opcode in evaluate_boolean_expression: %d", | |
1400 | expr -> op); | |
1401 | return 0; | |
9f7050df | 1402 | |
800f0de7 TL |
1403 | case expr_function: |
1404 | log_error ("function definition in evaluate_boolean_expr"); | |
1405 | return 0; | |
1406 | ||
9f7050df TL |
1407 | case expr_arg: |
1408 | break; | |
33e712ea | 1409 | } |
d7837182 | 1410 | |
5ce6b576 TL |
1411 | log_error ("Bogus opcode in evaluate_boolean_expression: %d", |
1412 | expr -> op); | |
33e712ea | 1413 | return 0; |
d7837182 | 1414 | } |
33e712ea | 1415 | |
16121af5 | 1416 | int evaluate_data_expression (result, packet, lease, client_state, |
d758ad8c | 1417 | in_options, cfg_options, scope, expr, file, line) |
1d07a807 | 1418 | struct data_string *result; |
33e712ea | 1419 | struct packet *packet; |
da38df14 | 1420 | struct lease *lease; |
16121af5 | 1421 | struct client_state *client_state; |
4038ec52 TL |
1422 | struct option_state *in_options; |
1423 | struct option_state *cfg_options; | |
6ceb9118 | 1424 | struct binding_scope **scope; |
33e712ea | 1425 | struct expression *expr; |
d758ad8c TL |
1426 | const char *file; |
1427 | int line; | |
33e712ea | 1428 | { |
1d07a807 | 1429 | struct data_string data, other; |
069e9f4c | 1430 | unsigned long offset, len, i; |
1d07a807 | 1431 | int s0, s1, s2, s3; |
da38df14 | 1432 | int status; |
2e236508 | 1433 | struct binding *binding; |
2727c1cf | 1434 | unsigned char *s; |
9f7050df | 1435 | struct binding_value *bv; |
33e712ea TL |
1436 | |
1437 | switch (expr -> op) { | |
1438 | /* Extract N bytes starting at byte M of a data string. */ | |
1439 | case expr_substring: | |
1d07a807 | 1440 | memset (&data, 0, sizeof data); |
4038ec52 | 1441 | s0 = evaluate_data_expression (&data, packet, lease, |
16121af5 | 1442 | client_state, |
4cbc378f | 1443 | in_options, cfg_options, scope, |
d758ad8c TL |
1444 | expr -> data.substring.expr, |
1445 | MDL); | |
33e712ea TL |
1446 | |
1447 | /* Evaluate the offset and length. */ | |
1d07a807 | 1448 | s1 = evaluate_numeric_expression |
16121af5 TL |
1449 | (&offset, packet, lease, client_state, in_options, |
1450 | cfg_options, scope, expr -> data.substring.offset); | |
4038ec52 | 1451 | s2 = evaluate_numeric_expression (&len, packet, lease, |
16121af5 | 1452 | client_state, |
4038ec52 | 1453 | in_options, cfg_options, |
4cbc378f | 1454 | scope, |
1d07a807 | 1455 | expr -> data.substring.len); |
33e712ea | 1456 | |
8b252b42 TL |
1457 | if (s0 && s1 && s2) { |
1458 | /* If the offset is after end of the string, | |
1459 | return an empty string. Otherwise, do the | |
1460 | adjustments and return what's left. */ | |
1461 | if (data.len > offset) { | |
d758ad8c | 1462 | data_string_copy (result, &data, file, line); |
8b252b42 TL |
1463 | result -> len -= offset; |
1464 | if (result -> len > len) { | |
1465 | result -> len = len; | |
1466 | result -> terminated = 0; | |
1467 | } | |
1468 | result -> data += offset; | |
1d07a807 | 1469 | } |
1d07a807 TL |
1470 | s3 = 1; |
1471 | } else | |
1472 | s3 = 0; | |
1473 | ||
1474 | #if defined (DEBUG_EXPRESSIONS) | |
27b3a58f | 1475 | log_debug ("data: substring (%s, %s, %s) = %s", |
1d07a807 TL |
1476 | s0 ? print_hex_1 (data.len, data.data, 30) : "NULL", |
1477 | s1 ? print_dec_1 (offset) : "NULL", | |
1478 | s2 ? print_dec_2 (len) : "NULL", | |
1479 | (s3 ? print_hex_2 (result -> len, result -> data, 30) | |
1480 | : "NULL")); | |
1481 | #endif | |
4cbc378f TL |
1482 | if (s0) |
1483 | data_string_forget (&data, MDL); | |
1d07a807 TL |
1484 | if (s3) |
1485 | return 1; | |
1d07a807 | 1486 | return 0; |
33e712ea | 1487 | |
33e712ea TL |
1488 | /* Extract the last N bytes of a data string. */ |
1489 | case expr_suffix: | |
1d07a807 | 1490 | memset (&data, 0, sizeof data); |
4038ec52 | 1491 | s0 = evaluate_data_expression (&data, packet, lease, |
16121af5 | 1492 | client_state, |
4cbc378f | 1493 | in_options, cfg_options, scope, |
d758ad8c | 1494 | expr -> data.suffix.expr, MDL); |
33e712ea | 1495 | /* Evaluate the length. */ |
4038ec52 | 1496 | s1 = evaluate_numeric_expression (&len, packet, lease, |
16121af5 | 1497 | client_state, |
4038ec52 | 1498 | in_options, cfg_options, |
4cbc378f | 1499 | scope, |
a5fc6758 | 1500 | expr -> data.suffix.len); |
1d07a807 | 1501 | if (s0 && s1) { |
d758ad8c | 1502 | data_string_copy (result, &data, file, line); |
1d07a807 TL |
1503 | |
1504 | /* If we are returning the last N bytes of a | |
1505 | string whose length is <= N, just return | |
1506 | the string - otherwise, compute a new | |
1507 | starting address and decrease the | |
1508 | length. */ | |
1509 | if (data.len > len) { | |
1510 | result -> data += data.len - len; | |
1511 | result -> len = len; | |
1512 | } | |
d758ad8c | 1513 | data_string_forget (&data, MDL); |
1d07a807 | 1514 | } |
33e712ea | 1515 | |
1d07a807 | 1516 | #if defined (DEBUG_EXPRESSIONS) |
06afba54 | 1517 | log_debug ("data: suffix (%s, %s) = %s", |
1d07a807 TL |
1518 | s0 ? print_hex_1 (data.len, data.data, 30) : "NULL", |
1519 | s1 ? print_dec_1 (len) : "NULL", | |
1520 | ((s0 && s1) | |
1521 | ? print_hex_2 (result -> len, result -> data, 30) | |
06afba54 | 1522 | : "NULL")); |
1d07a807 | 1523 | #endif |
20a767d3 | 1524 | return s0 && s1; |
33e712ea | 1525 | |
2727c1cf DH |
1526 | /* Convert string to lowercase. */ |
1527 | case expr_lcase: | |
1528 | memset(&data, 0, sizeof data); | |
1529 | s0 = evaluate_data_expression(&data, packet, lease, | |
1530 | client_state, | |
1531 | in_options, cfg_options, scope, | |
1532 | expr->data.lcase, MDL); | |
1533 | s1 = 0; | |
1534 | if (s0) { | |
1535 | result->len = data.len; | |
1536 | if (buffer_allocate(&result->buffer, | |
1537 | result->len + data.terminated, | |
1538 | MDL)) { | |
1539 | result->data = &result->buffer->data[0]; | |
1540 | memcpy(result->buffer->data, data.data, | |
1541 | data.len + data.terminated); | |
1542 | result->terminated = data.terminated; | |
1543 | s = (unsigned char *)result->data; | |
1544 | for (i = 0; i < result->len; i++, s++) | |
1545 | *s = tolower(*s); | |
1546 | s1 = 1; | |
1547 | } else { | |
1548 | log_error("data: lcase: no buffer memory."); | |
1549 | } | |
1550 | } | |
1551 | ||
1552 | #if defined (DEBUG_EXPRESSIONS) | |
1553 | log_debug("data: lcase (%s) = %s", | |
1554 | s0 ? print_hex_1(data.len, data.data, 30) : "NULL", | |
1555 | s1 ? print_hex_2(result->len, result->data, 30) | |
1556 | : "NULL"); | |
1557 | #endif | |
1558 | if (s0) | |
1559 | data_string_forget(&data, MDL); | |
1560 | return s1; | |
1561 | ||
1562 | /* Convert string to uppercase. */ | |
1563 | case expr_ucase: | |
1564 | memset(&data, 0, sizeof data); | |
1565 | s0 = evaluate_data_expression(&data, packet, lease, | |
1566 | client_state, | |
1567 | in_options, cfg_options, scope, | |
1568 | expr->data.lcase, MDL); | |
1569 | s1 = 0; | |
1570 | if (s0) { | |
1571 | result->len = data.len; | |
1572 | if (buffer_allocate(&result->buffer, | |
1573 | result->len + data.terminated, | |
1574 | file, line)) { | |
1575 | result->data = &result->buffer->data[0]; | |
1576 | memcpy(result->buffer->data, data.data, | |
1577 | data.len + data.terminated); | |
1578 | result->terminated = data.terminated; | |
1579 | s = (unsigned char *)result->data; | |
1580 | for (i = 0; i < result->len; i++, s++) | |
1581 | *s = toupper(*s); | |
1582 | s1 = 1; | |
1583 | } else { | |
1584 | log_error("data: lcase: no buffer memory."); | |
1585 | } | |
1586 | } | |
1587 | ||
1588 | #if defined (DEBUG_EXPRESSIONS) | |
1589 | log_debug("data: ucase (%s) = %s", | |
1590 | s0 ? print_hex_1(data.len, data.data, 30) : "NULL", | |
1591 | s1 ? print_hex_2(result->len, result->data, 30) | |
1592 | : "NULL"); | |
1593 | #endif | |
1594 | if (s0) | |
1595 | data_string_forget(&data, MDL); | |
1596 | return s1; | |
1597 | ||
33e712ea TL |
1598 | /* Extract an option. */ |
1599 | case expr_option: | |
4038ec52 | 1600 | if (in_options) |
d758ad8c TL |
1601 | s0 = get_option (result, |
1602 | expr -> data.option -> universe, | |
1603 | packet, lease, client_state, | |
1604 | in_options, cfg_options, in_options, | |
1605 | scope, expr -> data.option -> code, | |
1606 | file, line); | |
10da3e76 TL |
1607 | else |
1608 | s0 = 0; | |
f594d52c | 1609 | |
1d07a807 | 1610 | #if defined (DEBUG_EXPRESSIONS) |
27b3a58f | 1611 | log_debug ("data: option %s.%s = %s", |
1d07a807 TL |
1612 | expr -> data.option -> universe -> name, |
1613 | expr -> data.option -> name, | |
1614 | s0 ? print_hex_1 (result -> len, result -> data, 60) | |
1615 | : "NULL"); | |
1616 | #endif | |
1617 | return s0; | |
33e712ea | 1618 | |
e23f8b44 | 1619 | case expr_config_option: |
4038ec52 | 1620 | if (cfg_options) |
d758ad8c TL |
1621 | s0 = get_option (result, |
1622 | expr -> data.option -> universe, | |
1623 | packet, lease, client_state, | |
1624 | in_options, cfg_options, cfg_options, | |
1625 | scope, expr -> data.option -> code, | |
1626 | file, line); | |
e23f8b44 TL |
1627 | else |
1628 | s0 = 0; | |
1629 | ||
1630 | #if defined (DEBUG_EXPRESSIONS) | |
1631 | log_debug ("data: config-option %s.%s = %s", | |
1632 | expr -> data.option -> universe -> name, | |
1633 | expr -> data.option -> name, | |
1634 | s0 ? print_hex_1 (result -> len, result -> data, 60) | |
1635 | : "NULL"); | |
1636 | #endif | |
1637 | return s0; | |
1638 | ||
33e712ea TL |
1639 | /* Combine the hardware type and address. */ |
1640 | case expr_hardware: | |
d758ad8c TL |
1641 | /* On the client, hardware is our hardware. */ |
1642 | if (client_state) { | |
1643 | memset (result, 0, sizeof *result); | |
1644 | result -> data = | |
1645 | client_state -> interface -> hw_address.hbuf; | |
1646 | result -> len = | |
1647 | client_state -> interface -> hw_address.hlen; | |
1648 | #if defined (DEBUG_EXPRESSIONS) | |
1649 | log_debug ("data: hardware = %s", | |
1650 | print_hex_1 (result -> len, | |
1651 | result -> data, 60)); | |
1652 | #endif | |
1653 | return 1; | |
1654 | } | |
1655 | ||
1656 | /* The server cares about the client's hardware address, | |
1657 | so only in the case where we are examining a packet can | |
1658 | we return anything. */ | |
1d07a807 | 1659 | if (!packet || !packet -> raw) { |
8ae2d595 | 1660 | log_error ("data: hardware: raw packet not available"); |
1d07a807 TL |
1661 | return 0; |
1662 | } | |
8b252b42 TL |
1663 | if (packet -> raw -> hlen > sizeof packet -> raw -> chaddr) { |
1664 | log_error ("data: hardware: invalid hlen (%d)\n", | |
1665 | packet -> raw -> hlen); | |
1666 | return 0; | |
1667 | } | |
1d07a807 | 1668 | result -> len = packet -> raw -> hlen + 1; |
d758ad8c TL |
1669 | if (buffer_allocate (&result -> buffer, result -> len, |
1670 | file, line)) { | |
1d07a807 | 1671 | result -> data = &result -> buffer -> data [0]; |
b1b7b521 TL |
1672 | result -> buffer -> data [0] = packet -> raw -> htype; |
1673 | memcpy (&result -> buffer -> data [1], | |
1674 | packet -> raw -> chaddr, | |
33e712ea | 1675 | packet -> raw -> hlen); |
1d07a807 TL |
1676 | result -> terminated = 0; |
1677 | } else { | |
8ae2d595 | 1678 | log_error ("data: hardware: no memory for buffer."); |
1d07a807 | 1679 | return 0; |
33e712ea | 1680 | } |
1d07a807 | 1681 | #if defined (DEBUG_EXPRESSIONS) |
27b3a58f | 1682 | log_debug ("data: hardware = %s", |
1d07a807 TL |
1683 | print_hex_1 (result -> len, result -> data, 60)); |
1684 | #endif | |
1685 | return 1; | |
33e712ea TL |
1686 | |
1687 | /* Extract part of the raw packet. */ | |
1688 | case expr_packet: | |
1d07a807 | 1689 | if (!packet || !packet -> raw) { |
8ae2d595 | 1690 | log_error ("data: packet: raw packet not available"); |
1d07a807 | 1691 | return 0; |
33e712ea | 1692 | } |
1d07a807 | 1693 | |
7b4f1c06 | 1694 | s0 = evaluate_numeric_expression (&offset, packet, lease, |
16121af5 | 1695 | client_state, |
4038ec52 | 1696 | in_options, cfg_options, |
4cbc378f | 1697 | scope, |
7b4f1c06 TL |
1698 | expr -> data.packet.offset); |
1699 | s1 = evaluate_numeric_expression (&len, | |
16121af5 | 1700 | packet, lease, client_state, |
4038ec52 | 1701 | in_options, cfg_options, |
4cbc378f | 1702 | scope, |
1d07a807 TL |
1703 | expr -> data.packet.len); |
1704 | if (s0 && s1 && offset < packet -> packet_length) { | |
1705 | if (offset + len > packet -> packet_length) | |
1706 | result -> len = | |
1707 | packet -> packet_length - offset; | |
1708 | else | |
1709 | result -> len = len; | |
4cbc378f | 1710 | if (buffer_allocate (&result -> buffer, |
d758ad8c | 1711 | result -> len, file, line)) { |
1d07a807 | 1712 | result -> data = &result -> buffer -> data [0]; |
b1b7b521 | 1713 | memcpy (result -> buffer -> data, |
1d07a807 TL |
1714 | (((unsigned char *)(packet -> raw)) |
1715 | + offset), result -> len); | |
1716 | result -> terminated = 0; | |
1717 | } else { | |
10da3e76 | 1718 | log_error ("data: packet: no buffer memory."); |
1d07a807 TL |
1719 | return 0; |
1720 | } | |
1721 | s2 = 1; | |
1722 | } else | |
1723 | s2 = 0; | |
1724 | #if defined (DEBUG_EXPRESSIONS) | |
06afba54 | 1725 | log_debug ("data: packet (%ld, %ld) = %s", |
1d07a807 TL |
1726 | offset, len, |
1727 | s2 ? print_hex_1 (result -> len, | |
1728 | result -> data, 60) : NULL); | |
1729 | #endif | |
1730 | return s2; | |
33e712ea | 1731 | |
dd6e44a5 TL |
1732 | /* The encapsulation of all defined options in an |
1733 | option space... */ | |
1734 | case expr_encapsulate: | |
4038ec52 | 1735 | if (cfg_options) |
10da3e76 | 1736 | s0 = option_space_encapsulate |
16121af5 | 1737 | (result, packet, lease, client_state, |
4cbc378f | 1738 | in_options, cfg_options, scope, |
da38df14 | 1739 | &expr -> data.encapsulate); |
10da3e76 TL |
1740 | else |
1741 | s0 = 0; | |
1742 | ||
dd6e44a5 | 1743 | #if defined (DEBUG_EXPRESSIONS) |
27b3a58f | 1744 | log_debug ("data: encapsulate (%s) = %s", |
0f803d34 TL |
1745 | expr -> data.encapsulate.data, |
1746 | s0 ? print_hex_1 (result -> len, | |
4cbc378f | 1747 | result -> data, 60) : "NULL"); |
dd6e44a5 | 1748 | #endif |
0f803d34 | 1749 | return s0; |
dd6e44a5 | 1750 | |
33e712ea TL |
1751 | /* Some constant data... */ |
1752 | case expr_const_data: | |
1d07a807 | 1753 | #if defined (DEBUG_EXPRESSIONS) |
27b3a58f | 1754 | log_debug ("data: const = %s", |
1d07a807 TL |
1755 | print_hex_1 (expr -> data.const_data.len, |
1756 | expr -> data.const_data.data, 60)); | |
1757 | #endif | |
1758 | data_string_copy (result, | |
d758ad8c | 1759 | &expr -> data.const_data, file, line); |
1d07a807 | 1760 | return 1; |
33e712ea TL |
1761 | |
1762 | /* Hostname lookup... */ | |
1763 | case expr_host_lookup: | |
1d07a807 TL |
1764 | s0 = do_host_lookup (result, expr -> data.host_lookup); |
1765 | #if defined (DEBUG_EXPRESSIONS) | |
27b3a58f | 1766 | log_debug ("data: DNS lookup (%s) = %s", |
1d07a807 TL |
1767 | expr -> data.host_lookup -> hostname, |
1768 | (s0 | |
1769 | ? print_dotted_quads (result -> len, result -> data) | |
1770 | : "NULL")); | |
1771 | #endif | |
1772 | return s0; | |
33e712ea TL |
1773 | |
1774 | /* Concatenation... */ | |
1775 | case expr_concat: | |
1d07a807 | 1776 | memset (&data, 0, sizeof data); |
4038ec52 | 1777 | s0 = evaluate_data_expression (&data, packet, lease, |
16121af5 | 1778 | client_state, |
4cbc378f | 1779 | in_options, cfg_options, scope, |
d758ad8c | 1780 | expr -> data.concat [0], MDL); |
cd038e3e | 1781 | memset (&other, 0, sizeof other); |
4038ec52 | 1782 | s1 = evaluate_data_expression (&other, packet, lease, |
16121af5 | 1783 | client_state, |
4cbc378f | 1784 | in_options, cfg_options, scope, |
d758ad8c | 1785 | expr -> data.concat [1], MDL); |
1d07a807 TL |
1786 | |
1787 | if (s0 && s1) { | |
d758ad8c TL |
1788 | result -> len = data.len + other.len; |
1789 | if (!buffer_allocate (&result -> buffer, | |
1790 | (result -> len + other.terminated), | |
1791 | file, line)) { | |
8ae2d595 | 1792 | log_error ("data: concat: no memory"); |
1d07a807 | 1793 | result -> len = 0; |
4cbc378f TL |
1794 | data_string_forget (&data, MDL); |
1795 | data_string_forget (&other, MDL); | |
1d07a807 TL |
1796 | return 0; |
1797 | } | |
1798 | result -> data = &result -> buffer -> data [0]; | |
b1b7b521 TL |
1799 | memcpy (result -> buffer -> data, data.data, data.len); |
1800 | memcpy (&result -> buffer -> data [data.len], | |
1d07a807 | 1801 | other.data, other.len + other.terminated); |
d758ad8c TL |
1802 | } |
1803 | ||
1804 | if (s0) | |
4cbc378f | 1805 | data_string_forget (&data, MDL); |
d758ad8c | 1806 | if (s1) |
4cbc378f | 1807 | data_string_forget (&other, MDL); |
1d07a807 | 1808 | #if defined (DEBUG_EXPRESSIONS) |
27b3a58f | 1809 | log_debug ("data: concat (%s, %s) = %s", |
1d07a807 TL |
1810 | s0 ? print_hex_1 (data.len, data.data, 20) : "NULL", |
1811 | s1 ? print_hex_2 (other.len, other.data, 20) : "NULL", | |
b5b7abf8 | 1812 | ((s0 && s1) |
1d07a807 TL |
1813 | ? print_hex_3 (result -> len, result -> data, 30) |
1814 | : "NULL")); | |
1815 | #endif | |
b5b7abf8 | 1816 | return s0 && s1; |
33e712ea | 1817 | |
20a767d3 | 1818 | case expr_encode_int8: |
4038ec52 | 1819 | s0 = evaluate_numeric_expression (&len, packet, lease, |
16121af5 | 1820 | client_state, |
4038ec52 | 1821 | in_options, cfg_options, |
4cbc378f | 1822 | scope, |
3c98e80b | 1823 | expr -> data.encode_int); |
20a767d3 TL |
1824 | if (s0) { |
1825 | result -> len = 1; | |
d758ad8c TL |
1826 | if (!buffer_allocate (&result -> buffer, |
1827 | 1, file, line)) { | |
20a767d3 TL |
1828 | log_error ("data: encode_int8: no memory"); |
1829 | result -> len = 0; | |
1830 | s0 = 0; | |
1831 | } else { | |
1832 | result -> data = &result -> buffer -> data [0]; | |
b1b7b521 | 1833 | result -> buffer -> data [0] = len; |
20a767d3 TL |
1834 | } |
1835 | } else | |
1836 | result -> len = 0; | |
1837 | ||
1838 | #if defined (DEBUG_EXPRESSIONS) | |
1839 | if (!s0) | |
27b3a58f | 1840 | log_debug ("data: encode_int8 (NULL) = NULL"); |
20a767d3 | 1841 | else |
06afba54 | 1842 | log_debug ("data: encode_int8 (%ld) = %s", len, |
20a767d3 TL |
1843 | print_hex_2 (result -> len, |
1844 | result -> data, 20)); | |
1845 | #endif | |
1846 | return s0; | |
1847 | ||
1848 | ||
1849 | case expr_encode_int16: | |
4038ec52 | 1850 | s0 = evaluate_numeric_expression (&len, packet, lease, |
16121af5 | 1851 | client_state, |
4038ec52 | 1852 | in_options, cfg_options, |
4cbc378f | 1853 | scope, |
3c98e80b | 1854 | expr -> data.encode_int); |
20a767d3 TL |
1855 | if (s0) { |
1856 | result -> len = 2; | |
d758ad8c TL |
1857 | if (!buffer_allocate (&result -> buffer, 2, |
1858 | file, line)) { | |
20a767d3 TL |
1859 | log_error ("data: encode_int16: no memory"); |
1860 | result -> len = 0; | |
1861 | s0 = 0; | |
1862 | } else { | |
1863 | result -> data = &result -> buffer -> data [0]; | |
b1b7b521 | 1864 | putUShort (result -> buffer -> data, len); |
20a767d3 TL |
1865 | } |
1866 | } else | |
1867 | result -> len = 0; | |
1868 | ||
1869 | #if defined (DEBUG_EXPRESSIONS) | |
1870 | if (!s0) | |
27b3a58f | 1871 | log_debug ("data: encode_int16 (NULL) = NULL"); |
20a767d3 | 1872 | else |
06afba54 | 1873 | log_debug ("data: encode_int16 (%ld) = %s", len, |
20a767d3 TL |
1874 | print_hex_2 (result -> len, |
1875 | result -> data, 20)); | |
1876 | #endif | |
1877 | return s0; | |
1878 | ||
1879 | case expr_encode_int32: | |
4038ec52 | 1880 | s0 = evaluate_numeric_expression (&len, packet, lease, |
16121af5 | 1881 | client_state, |
4038ec52 | 1882 | in_options, cfg_options, |
4cbc378f | 1883 | scope, |
3c98e80b | 1884 | expr -> data.encode_int); |
20a767d3 TL |
1885 | if (s0) { |
1886 | result -> len = 4; | |
d758ad8c TL |
1887 | if (!buffer_allocate (&result -> buffer, 4, |
1888 | file, line)) { | |
20a767d3 TL |
1889 | log_error ("data: encode_int32: no memory"); |
1890 | result -> len = 0; | |
1891 | s0 = 0; | |
1892 | } else { | |
1893 | result -> data = &result -> buffer -> data [0]; | |
b1b7b521 | 1894 | putULong (result -> buffer -> data, len); |
20a767d3 TL |
1895 | } |
1896 | } else | |
1897 | result -> len = 0; | |
1898 | ||
1899 | #if defined (DEBUG_EXPRESSIONS) | |
1900 | if (!s0) | |
27b3a58f | 1901 | log_debug ("data: encode_int32 (NULL) = NULL"); |
20a767d3 | 1902 | else |
06afba54 | 1903 | log_debug ("data: encode_int32 (%ld) = %s", len, |
20a767d3 TL |
1904 | print_hex_2 (result -> len, |
1905 | result -> data, 20)); | |
1906 | #endif | |
1907 | return s0; | |
1908 | ||
da38df14 TL |
1909 | case expr_binary_to_ascii: |
1910 | /* Evaluate the base (offset) and width (len): */ | |
1911 | s0 = evaluate_numeric_expression | |
16121af5 TL |
1912 | (&offset, packet, lease, client_state, in_options, |
1913 | cfg_options, scope, expr -> data.b2a.base); | |
4038ec52 | 1914 | s1 = evaluate_numeric_expression (&len, packet, lease, |
16121af5 | 1915 | client_state, |
4038ec52 | 1916 | in_options, cfg_options, |
4cbc378f | 1917 | scope, |
644b8416 | 1918 | expr -> data.b2a.width); |
da38df14 | 1919 | |
c57db45c | 1920 | /* Evaluate the separator string. */ |
da38df14 | 1921 | memset (&data, 0, sizeof data); |
4038ec52 | 1922 | s2 = evaluate_data_expression (&data, packet, lease, |
16121af5 | 1923 | client_state, |
4cbc378f | 1924 | in_options, cfg_options, scope, |
c57db45c | 1925 | expr -> data.b2a.separator, |
d758ad8c | 1926 | MDL); |
da38df14 TL |
1927 | |
1928 | /* Evaluate the data to be converted. */ | |
1929 | memset (&other, 0, sizeof other); | |
4038ec52 | 1930 | s3 = evaluate_data_expression (&other, packet, lease, |
16121af5 | 1931 | client_state, |
4cbc378f | 1932 | in_options, cfg_options, scope, |
d758ad8c | 1933 | expr -> data.b2a.buffer, MDL); |
da38df14 TL |
1934 | |
1935 | if (s0 && s1 && s2 && s3) { | |
b1b7b521 | 1936 | unsigned buflen, i; |
da38df14 TL |
1937 | |
1938 | if (len != 8 && len != 16 && len != 32) { | |
ab58ff49 | 1939 | log_info ("binary_to_ascii: %s %ld!", |
da38df14 | 1940 | "invalid width", len); |
98311e4b | 1941 | status = 0; |
da38df14 TL |
1942 | goto b2a_out; |
1943 | } | |
1944 | len /= 8; | |
1945 | ||
1946 | /* The buffer must be a multiple of the number's | |
1947 | width. */ | |
1948 | if (other.len % len) { | |
ab58ff49 | 1949 | log_info ("binary-to-ascii: %s %d %s %ld!", |
da38df14 TL |
1950 | "length of buffer", other.len, |
1951 | "not a multiple of width", len); | |
1952 | status = 0; | |
1953 | goto b2a_out; | |
1954 | } | |
1955 | ||
1956 | /* Count the width of the output. */ | |
1957 | buflen = 0; | |
1958 | for (i = 0; i < other.len; i += len) { | |
1959 | if (len == 1) { | |
1960 | if (offset == 8) { | |
1961 | if (other.data [i] < 8) | |
1962 | buflen++; | |
1963 | else if (other.data [i] < 64) | |
1964 | buflen += 2; | |
1965 | else | |
1966 | buflen += 3; | |
1967 | } else if (offset == 10) { | |
1968 | if (other.data [i] < 10) | |
1969 | buflen++; | |
1970 | else if (other.data [i] < 100) | |
1971 | buflen += 2; | |
1972 | else | |
1973 | buflen += 3; | |
36ed3a00 | 1974 | } else if (offset == 16) { |
da38df14 TL |
1975 | if (other.data [i] < 16) |
1976 | buflen++; | |
1977 | else | |
1978 | buflen += 2; | |
1979 | } else | |
1980 | buflen += (converted_length | |
1981 | (&other.data [i], | |
1982 | offset, 1)); | |
1983 | } else | |
1984 | buflen += (converted_length | |
1985 | (&other.data [i], | |
1986 | offset, len)); | |
1987 | if (i + len != other.len) | |
1988 | buflen += data.len; | |
1989 | } | |
1990 | ||
4cbc378f | 1991 | if (!buffer_allocate (&result -> buffer, |
d758ad8c | 1992 | buflen + 1, file, line)) { |
da38df14 TL |
1993 | log_error ("data: binary-to-ascii: no memory"); |
1994 | status = 0; | |
1995 | goto b2a_out; | |
1996 | } | |
1997 | result -> data = &result -> buffer -> data [0]; | |
1998 | result -> len = buflen; | |
1999 | result -> terminated = 1; | |
2000 | ||
2001 | buflen = 0; | |
2002 | for (i = 0; i < other.len; i += len) { | |
2003 | buflen += (binary_to_ascii | |
b1b7b521 | 2004 | (&result -> buffer -> data [buflen], |
da38df14 TL |
2005 | &other.data [i], offset, len)); |
2006 | if (i + len != other.len) { | |
b1b7b521 TL |
2007 | memcpy (&result -> |
2008 | buffer -> data [buflen], | |
da38df14 TL |
2009 | data.data, data.len); |
2010 | buflen += data.len; | |
2011 | } | |
2012 | } | |
2013 | /* NUL terminate. */ | |
b1b7b521 | 2014 | result -> buffer -> data [buflen] = 0; |
da38df14 TL |
2015 | status = 1; |
2016 | } else | |
2017 | status = 0; | |
2018 | ||
2019 | b2a_out: | |
2020 | #if defined (DEBUG_EXPRESSIONS) | |
27b3a58f | 2021 | log_debug ("data: binary-to-ascii (%s, %s, %s, %s) = %s", |
da38df14 TL |
2022 | s0 ? print_dec_1 (offset) : "NULL", |
2023 | s1 ? print_dec_2 (len) : "NULL", | |
2024 | s2 ? print_hex_1 (data.len, data.data, 30) : "NULL", | |
2025 | s3 ? print_hex_2 (other.len, other.data, 30) : "NULL", | |
2026 | (status ? print_hex_3 (result -> len, result -> data, 30) | |
2027 | : "NULL")); | |
2028 | #endif | |
2029 | if (s2) | |
4cbc378f | 2030 | data_string_forget (&data, MDL); |
da38df14 | 2031 | if (s3) |
4cbc378f | 2032 | data_string_forget (&other, MDL); |
da38df14 TL |
2033 | if (status) |
2034 | return 1; | |
2035 | return 0; | |
2036 | ||
2037 | case expr_reverse: | |
2038 | /* Evaluate the width (len): */ | |
2039 | s0 = evaluate_numeric_expression | |
16121af5 TL |
2040 | (&len, packet, lease, client_state, in_options, |
2041 | cfg_options, scope, expr -> data.reverse.width); | |
da38df14 TL |
2042 | |
2043 | /* Evaluate the data. */ | |
2044 | memset (&data, 0, sizeof data); | |
4038ec52 | 2045 | s1 = evaluate_data_expression (&data, packet, lease, |
16121af5 | 2046 | client_state, |
4cbc378f | 2047 | in_options, cfg_options, scope, |
d758ad8c TL |
2048 | expr -> data.reverse.buffer, |
2049 | MDL); | |
da38df14 TL |
2050 | |
2051 | if (s0 && s1) { | |
2052 | char *upper; | |
2053 | int i; | |
2054 | ||
2055 | /* The buffer must be a multiple of the number's | |
2056 | width. */ | |
97a4f219 | 2057 | if (data.len % len) { |
ab58ff49 | 2058 | log_info ("reverse: %s %d %s %ld!", |
97a4f219 | 2059 | "length of buffer", data.len, |
da38df14 TL |
2060 | "not a multiple of width", len); |
2061 | status = 0; | |
2062 | goto reverse_out; | |
2063 | } | |
2064 | ||
2065 | /* XXX reverse in place? I don't think we can. */ | |
4cbc378f | 2066 | if (!buffer_allocate (&result -> buffer, |
d758ad8c | 2067 | data.len, file, line)) { |
da38df14 TL |
2068 | log_error ("data: reverse: no memory"); |
2069 | status = 0; | |
2070 | goto reverse_out; | |
2071 | } | |
2072 | result -> data = &result -> buffer -> data [0]; | |
2073 | result -> len = data.len; | |
2074 | result -> terminated = 0; | |
2075 | ||
2076 | for (i = 0; i < data.len; i += len) { | |
b1b7b521 | 2077 | memcpy (&result -> buffer -> data [i], |
da38df14 TL |
2078 | &data.data [data.len - i - len], len); |
2079 | } | |
2080 | status = 1; | |
2081 | } else | |
2082 | status = 0; | |
2083 | ||
2084 | reverse_out: | |
2085 | #if defined (DEBUG_EXPRESSIONS) | |
27b3a58f | 2086 | log_debug ("data: reverse (%s, %s) = %s", |
4f4d982c | 2087 | s0 ? print_dec_1 (len) : "NULL", |
da38df14 TL |
2088 | s1 ? print_hex_1 (data.len, data.data, 30) : "NULL", |
2089 | (status ? print_hex_3 (result -> len, result -> data, 30) | |
2090 | : "NULL")); | |
2091 | #endif | |
2092 | if (s0) | |
4cbc378f | 2093 | data_string_forget (&data, MDL); |
da38df14 TL |
2094 | if (status) |
2095 | return 1; | |
2096 | return 0; | |
2097 | ||
2098 | case expr_leased_address: | |
2099 | if (!lease) { | |
2bddf829 DH |
2100 | log_debug("data: \"leased-address\" configuration " |
2101 | "directive: there is no lease associated " | |
2102 | "with this client."); | |
da38df14 TL |
2103 | return 0; |
2104 | } | |
2105 | result -> len = lease -> ip_addr.len; | |
d758ad8c TL |
2106 | if (buffer_allocate (&result -> buffer, result -> len, |
2107 | file, line)) { | |
da38df14 | 2108 | result -> data = &result -> buffer -> data [0]; |
b1b7b521 | 2109 | memcpy (&result -> buffer -> data [0], |
da38df14 TL |
2110 | lease -> ip_addr.iabuf, lease -> ip_addr.len); |
2111 | result -> terminated = 0; | |
2112 | } else { | |
2113 | log_error ("data: leased-address: no memory."); | |
2114 | return 0; | |
2115 | } | |
2116 | #if defined (DEBUG_EXPRESSIONS) | |
27b3a58f | 2117 | log_debug ("data: leased-address = %s", |
da38df14 TL |
2118 | print_hex_1 (result -> len, result -> data, 60)); |
2119 | #endif | |
2120 | return 1; | |
2121 | ||
79a65726 TL |
2122 | case expr_pick_first_value: |
2123 | memset (&data, 0, sizeof data); | |
2124 | if ((evaluate_data_expression | |
16121af5 TL |
2125 | (result, packet, |
2126 | lease, client_state, in_options, cfg_options, | |
d758ad8c | 2127 | scope, expr -> data.pick_first_value.car, MDL))) { |
79a65726 | 2128 | #if defined (DEBUG_EXPRESSIONS) |
4b63da96 | 2129 | log_debug ("data: pick_first_value (%s, xxx)", |
0acdc228 TL |
2130 | print_hex_1 (result -> len, |
2131 | result -> data, 40)); | |
79a65726 TL |
2132 | #endif |
2133 | return 1; | |
2134 | } | |
2dbc95d6 TL |
2135 | |
2136 | if (expr -> data.pick_first_value.cdr && | |
2137 | (evaluate_data_expression | |
16121af5 TL |
2138 | (result, packet, |
2139 | lease, client_state, in_options, cfg_options, | |
d758ad8c | 2140 | scope, expr -> data.pick_first_value.cdr, MDL))) { |
79a65726 | 2141 | #if defined (DEBUG_EXPRESSIONS) |
0acdc228 TL |
2142 | log_debug ("data: pick_first_value (NULL, %s)", |
2143 | print_hex_1 (result -> len, | |
2144 | result -> data, 40)); | |
79a65726 TL |
2145 | #endif |
2146 | return 1; | |
2147 | } | |
2148 | ||
2149 | #if defined (DEBUG_EXPRESSIONS) | |
2dbc95d6 | 2150 | log_debug ("data: pick_first_value (NULL, NULL) = NULL"); |
79a65726 TL |
2151 | #endif |
2152 | return 0; | |
2153 | ||
2154 | case expr_host_decl_name: | |
2155 | if (!lease || !lease -> host) { | |
2156 | log_error ("data: host_decl_name: not available"); | |
2157 | return 0; | |
2158 | } | |
0acdc228 | 2159 | result -> len = strlen (lease -> host -> name); |
4cbc378f | 2160 | if (buffer_allocate (&result -> buffer, |
d758ad8c | 2161 | result -> len + 1, file, line)) { |
79a65726 | 2162 | result -> data = &result -> buffer -> data [0]; |
b1b7b521 | 2163 | strcpy ((char *)&result -> buffer -> data [0], |
06a8567c | 2164 | lease -> host -> name); |
79a65726 TL |
2165 | result -> terminated = 1; |
2166 | } else { | |
2167 | log_error ("data: host-decl-name: no memory."); | |
2168 | return 0; | |
2169 | } | |
2170 | #if defined (DEBUG_EXPRESSIONS) | |
2dbc95d6 | 2171 | log_debug ("data: host-decl-name = %s", lease -> host -> name); |
79a65726 TL |
2172 | #endif |
2173 | return 1; | |
da38df14 | 2174 | |
2e236508 | 2175 | case expr_null: |
846d7d54 | 2176 | #if defined (DEBUG_EXPRESSIONS) |
2e236508 | 2177 | log_debug ("data: null = NULL"); |
846d7d54 | 2178 | #endif |
2e236508 TL |
2179 | return 0; |
2180 | ||
2181 | case expr_variable_reference: | |
6ceb9118 TL |
2182 | if (scope && *scope) { |
2183 | binding = find_binding (*scope, expr -> data.variable); | |
4cbc378f | 2184 | |
6ceb9118 TL |
2185 | if (binding && binding -> value) { |
2186 | if (binding -> value -> type == binding_data) { | |
9f7050df TL |
2187 | data_string_copy (result, |
2188 | &binding -> value -> value.data, | |
d758ad8c | 2189 | file, line); |
9f7050df | 2190 | s0 = 1; |
6ceb9118 | 2191 | } else if (binding -> value -> type != binding_data) { |
9f7050df TL |
2192 | log_error ("binding type %d in %s.", |
2193 | binding -> value -> type, | |
2194 | "evaluate_data_expression"); | |
2195 | s0 = 0; | |
6ceb9118 | 2196 | } else |
9f7050df | 2197 | s0 = 0; |
6ceb9118 | 2198 | } else |
2e236508 | 2199 | s0 = 0; |
6ceb9118 TL |
2200 | } else |
2201 | s0 = 0; | |
06a8567c | 2202 | #if defined (DEBUG_EXPRESSIONS) |
0e97ecc8 | 2203 | log_debug ("data: %s = %s", expr -> data.variable, |
2e236508 | 2204 | s0 ? print_hex_1 (result -> len, |
9f7050df | 2205 | result -> data, 50) : "NULL"); |
06a8567c | 2206 | #endif |
2e236508 | 2207 | return s0; |
06a8567c | 2208 | |
9f7050df TL |
2209 | case expr_funcall: |
2210 | bv = (struct binding_value *)0; | |
16121af5 | 2211 | s0 = evaluate_expression (&bv, packet, lease, client_state, |
9f7050df | 2212 | in_options, cfg_options, |
d758ad8c | 2213 | scope, expr, MDL); |
9f7050df TL |
2214 | if (s0) { |
2215 | if (bv -> type != binding_data) | |
2216 | log_error ("%s() returned type %d in %s.", | |
2217 | expr -> data.funcall.name, | |
2218 | bv -> type, | |
2219 | "evaluate_data_expression"); | |
2220 | else | |
2221 | data_string_copy (result, &bv -> value.data, | |
d758ad8c | 2222 | file, line); |
9f7050df TL |
2223 | binding_value_dereference (&bv, MDL); |
2224 | } | |
2225 | #if defined (DEBUG_EXPRESSIONS) | |
0e97ecc8 | 2226 | log_debug ("data: %s = %s", expr -> data.funcall.name, |
9f7050df TL |
2227 | s0 ? print_hex_1 (result -> len, |
2228 | result -> data, 50) : "NULL"); | |
2229 | #endif | |
2230 | break; | |
2231 | ||
4cbc378f TL |
2232 | /* Extract the filename. */ |
2233 | case expr_filename: | |
2234 | if (packet && packet -> raw -> file [0]) { | |
2235 | char *fn = | |
2236 | memchr (packet -> raw -> file, 0, | |
2237 | sizeof packet -> raw -> file); | |
2238 | if (!fn) | |
2239 | fn = ((char *)packet -> raw -> file + | |
2240 | sizeof packet -> raw -> file); | |
2241 | result -> len = fn - &(packet -> raw -> file [0]); | |
2242 | if (buffer_allocate (&result -> buffer, | |
d758ad8c | 2243 | result -> len + 1, file, line)) { |
4cbc378f TL |
2244 | result -> data = &result -> buffer -> data [0]; |
2245 | memcpy (&result -> buffer -> data [0], | |
2246 | packet -> raw -> file, | |
2247 | result -> len); | |
2248 | result -> buffer -> data [result -> len] = 0; | |
2249 | result -> terminated = 1; | |
2250 | s0 = 1; | |
2251 | } else { | |
2252 | log_error ("data: filename: no memory."); | |
2253 | s0 = 0; | |
2254 | } | |
2255 | } else | |
2256 | s0 = 0; | |
2257 | ||
2258 | #if defined (DEBUG_EXPRESSIONS) | |
2259 | log_info ("data: filename = \"%s\"", | |
16121af5 | 2260 | s0 ? (const char *)(result -> data) : "NULL"); |
4cbc378f TL |
2261 | #endif |
2262 | return s0; | |
2263 | ||
2264 | /* Extract the server name. */ | |
2265 | case expr_sname: | |
2266 | if (packet && packet -> raw -> sname [0]) { | |
2267 | char *fn = | |
2268 | memchr (packet -> raw -> sname, 0, | |
2269 | sizeof packet -> raw -> sname); | |
2270 | if (!fn) | |
2271 | fn = ((char *)packet -> raw -> sname + | |
2272 | sizeof packet -> raw -> sname); | |
2273 | result -> len = fn - &packet -> raw -> sname [0]; | |
2274 | if (buffer_allocate (&result -> buffer, | |
d758ad8c | 2275 | result -> len + 1, file, line)) { |
4cbc378f TL |
2276 | result -> data = &result -> buffer -> data [0]; |
2277 | memcpy (&result -> buffer -> data [0], | |
2278 | packet -> raw -> sname, | |
2279 | result -> len); | |
2280 | result -> buffer -> data [result -> len] = 0; | |
2281 | result -> terminated = 1; | |
2282 | s0 = 1; | |
2283 | } else { | |
2284 | log_error ("data: sname: no memory."); | |
2285 | s0 = 0; | |
2286 | } | |
2287 | } else | |
2288 | s0 = 0; | |
2289 | ||
2290 | #if defined (DEBUG_EXPRESSIONS) | |
2291 | log_info ("data: sname = \"%s\"", | |
16121af5 | 2292 | s0 ? (const char *)(result -> data) : "NULL"); |
4cbc378f TL |
2293 | #endif |
2294 | return s0; | |
2295 | ||
33e712ea TL |
2296 | case expr_check: |
2297 | case expr_equal: | |
2b965a44 | 2298 | case expr_not_equal: |
33e712ea TL |
2299 | case expr_and: |
2300 | case expr_or: | |
2301 | case expr_not: | |
1d07a807 | 2302 | case expr_match: |
1c5d5731 | 2303 | case expr_static: |
5ce6b576 | 2304 | case expr_known: |
b1b7b521 TL |
2305 | case expr_none: |
2306 | case expr_exists: | |
2e236508 | 2307 | case expr_variable_exists: |
8ae2d595 | 2308 | log_error ("Boolean opcode in evaluate_data_expression: %d", |
33e712ea | 2309 | expr -> op); |
1d07a807 | 2310 | return 0; |
33e712ea TL |
2311 | |
2312 | case expr_extract_int8: | |
2313 | case expr_extract_int16: | |
2314 | case expr_extract_int32: | |
2315 | case expr_const_int: | |
cd31814f | 2316 | case expr_lease_time: |
4bae15ec | 2317 | case expr_dns_transaction: |
800f0de7 TL |
2318 | case expr_add: |
2319 | case expr_subtract: | |
2320 | case expr_multiply: | |
2321 | case expr_divide: | |
2322 | case expr_remainder: | |
3c98e80b DN |
2323 | case expr_binary_and: |
2324 | case expr_binary_or: | |
2325 | case expr_binary_xor: | |
16121af5 | 2326 | case expr_client_state: |
8ae2d595 | 2327 | log_error ("Numeric opcode in evaluate_data_expression: %d", |
33e712ea | 2328 | expr -> op); |
1d07a807 | 2329 | return 0; |
4bae15ec | 2330 | |
2e236508 | 2331 | case expr_ns_add: |
4bae15ec TL |
2332 | case expr_ns_delete: |
2333 | case expr_ns_exists: | |
2334 | case expr_ns_not_exists: | |
2335 | log_error ("dns update opcode in evaluate_data_expression: %d", | |
2336 | expr -> op); | |
2337 | return 0; | |
800f0de7 TL |
2338 | |
2339 | case expr_function: | |
2340 | log_error ("function definition in evaluate_data_expression"); | |
2341 | return 0; | |
2342 | ||
2343 | case expr_arg: | |
2344 | break; | |
33e712ea TL |
2345 | } |
2346 | ||
8ae2d595 | 2347 | log_error ("Bogus opcode in evaluate_data_expression: %d", expr -> op); |
1d07a807 | 2348 | return 0; |
33e712ea TL |
2349 | } |
2350 | ||
16121af5 | 2351 | int evaluate_numeric_expression (result, packet, lease, client_state, |
4cbc378f | 2352 | in_options, cfg_options, scope, expr) |
1d07a807 | 2353 | unsigned long *result; |
33e712ea | 2354 | struct packet *packet; |
da38df14 | 2355 | struct lease *lease; |
16121af5 | 2356 | struct client_state *client_state; |
4038ec52 TL |
2357 | struct option_state *in_options; |
2358 | struct option_state *cfg_options; | |
6ceb9118 | 2359 | struct binding_scope **scope; |
33e712ea TL |
2360 | struct expression *expr; |
2361 | { | |
2362 | struct data_string data; | |
622b2817 | 2363 | int status, sleft, sright; |
4bd8800e | 2364 | #if defined (NSUPDATE) |
4bae15ec | 2365 | ns_updrec *nut; |
4bae15ec | 2366 | ns_updque uq; |
4bd8800e | 2367 | #endif |
4bae15ec | 2368 | struct expression *cur, *next; |
9f7050df TL |
2369 | struct binding *binding; |
2370 | struct binding_value *bv; | |
800f0de7 | 2371 | unsigned long ileft, iright; |
33e712ea TL |
2372 | |
2373 | switch (expr -> op) { | |
2374 | case expr_check: | |
2375 | case expr_equal: | |
2b965a44 | 2376 | case expr_not_equal: |
33e712ea TL |
2377 | case expr_and: |
2378 | case expr_or: | |
2379 | case expr_not: | |
1d07a807 | 2380 | case expr_match: |
1c5d5731 | 2381 | case expr_static: |
5ce6b576 | 2382 | case expr_known: |
b1b7b521 TL |
2383 | case expr_none: |
2384 | case expr_exists: | |
2e236508 | 2385 | case expr_variable_exists: |
8ae2d595 | 2386 | log_error ("Boolean opcode in evaluate_numeric_expression: %d", |
33e712ea TL |
2387 | expr -> op); |
2388 | return 0; | |
2389 | ||
2390 | case expr_substring: | |
2391 | case expr_suffix: | |
2727c1cf DH |
2392 | case expr_lcase: |
2393 | case expr_ucase: | |
33e712ea TL |
2394 | case expr_option: |
2395 | case expr_hardware: | |
2396 | case expr_const_data: | |
2397 | case expr_packet: | |
2398 | case expr_concat: | |
dd6e44a5 | 2399 | case expr_encapsulate: |
33e712ea | 2400 | case expr_host_lookup: |
20a767d3 TL |
2401 | case expr_encode_int8: |
2402 | case expr_encode_int16: | |
2403 | case expr_encode_int32: | |
da38df14 TL |
2404 | case expr_binary_to_ascii: |
2405 | case expr_reverse: | |
4cbc378f TL |
2406 | case expr_filename: |
2407 | case expr_sname: | |
79a65726 TL |
2408 | case expr_pick_first_value: |
2409 | case expr_host_decl_name: | |
2410 | case expr_config_option: | |
da38df14 | 2411 | case expr_leased_address: |
2e236508 | 2412 | case expr_null: |
8ae2d595 | 2413 | log_error ("Data opcode in evaluate_numeric_expression: %d", |
33e712ea TL |
2414 | expr -> op); |
2415 | return 0; | |
2416 | ||
2417 | case expr_extract_int8: | |
1d07a807 TL |
2418 | memset (&data, 0, sizeof data); |
2419 | status = evaluate_data_expression | |
16121af5 | 2420 | (&data, packet, lease, client_state, in_options, |
d758ad8c | 2421 | cfg_options, scope, expr -> data.extract_int, MDL); |
1d07a807 TL |
2422 | if (status) |
2423 | *result = data.data [0]; | |
2424 | #if defined (DEBUG_EXPRESSIONS) | |
27b3a58f | 2425 | log_debug ("num: extract_int8 (%s) = %s", |
1d07a807 TL |
2426 | status ? print_hex_1 (data.len, data.data, 60) : "NULL", |
2427 | status ? print_dec_1 (*result) : "NULL" ); | |
2428 | #endif | |
4cbc378f | 2429 | if (status) data_string_forget (&data, MDL); |
1d07a807 | 2430 | return status; |
33e712ea TL |
2431 | |
2432 | case expr_extract_int16: | |
1d07a807 TL |
2433 | memset (&data, 0, sizeof data); |
2434 | status = (evaluate_data_expression | |
16121af5 | 2435 | (&data, packet, lease, client_state, in_options, |
d758ad8c | 2436 | cfg_options, scope, expr -> data.extract_int, MDL)); |
1d07a807 TL |
2437 | if (status && data.len >= 2) |
2438 | *result = getUShort (data.data); | |
2439 | #if defined (DEBUG_EXPRESSIONS) | |
27b3a58f | 2440 | log_debug ("num: extract_int16 (%s) = %ld", |
1d07a807 TL |
2441 | ((status && data.len >= 2) ? |
2442 | print_hex_1 (data.len, data.data, 60) : "NULL"), | |
2443 | *result); | |
2444 | #endif | |
4cbc378f | 2445 | if (status) data_string_forget (&data, MDL); |
1d07a807 | 2446 | return (status && data.len >= 2); |
33e712ea TL |
2447 | |
2448 | case expr_extract_int32: | |
1d07a807 TL |
2449 | memset (&data, 0, sizeof data); |
2450 | status = (evaluate_data_expression | |
16121af5 | 2451 | (&data, packet, lease, client_state, in_options, |
d758ad8c | 2452 | cfg_options, scope, expr -> data.extract_int, MDL)); |
1d07a807 TL |
2453 | if (status && data.len >= 4) |
2454 | *result = getULong (data.data); | |
2455 | #if defined (DEBUG_EXPRESSIONS) | |
27b3a58f | 2456 | log_debug ("num: extract_int32 (%s) = %ld", |
1d07a807 TL |
2457 | ((status && data.len >= 4) ? |
2458 | print_hex_1 (data.len, data.data, 60) : "NULL"), | |
2459 | *result); | |
2460 | #endif | |
4cbc378f | 2461 | if (status) data_string_forget (&data, MDL); |
1d07a807 | 2462 | return (status && data.len >= 4); |
33e712ea TL |
2463 | |
2464 | case expr_const_int: | |
1d07a807 | 2465 | *result = expr -> data.const_int; |
cd31814f | 2466 | #if defined (DEBUG_EXPRESSIONS) |
06afba54 | 2467 | log_debug ("number: CONSTANT = %ld", *result); |
cd31814f | 2468 | #endif |
1d07a807 | 2469 | return 1; |
069e9f4c | 2470 | |
cd31814f TL |
2471 | case expr_lease_time: |
2472 | if (!lease) { | |
4f4d982c TL |
2473 | log_error ("data: leased_lease: not available"); |
2474 | return 0; | |
2475 | } | |
2476 | if (lease -> ends < cur_time) { | |
2477 | log_error ("%s %lu when it is now %lu", | |
2478 | "data: lease_time: lease ends at", | |
c4661845 | 2479 | (long)(lease -> ends), (long)cur_time); |
cd31814f TL |
2480 | return 0; |
2481 | } | |
2482 | *result = lease -> ends - cur_time; | |
2483 | #if defined (DEBUG_EXPRESSIONS) | |
06afba54 TL |
2484 | log_debug ("number: lease-time = (%lu - %lu) = %ld", |
2485 | lease -> ends, | |
4f4d982c | 2486 | cur_time, *result); |
cd31814f TL |
2487 | #endif |
2488 | return 1; | |
2489 | ||
4bae15ec TL |
2490 | case expr_dns_transaction: |
2491 | #if !defined (NSUPDATE) | |
2492 | return 0; | |
2493 | #else | |
7167c654 TL |
2494 | if (!resolver_inited) { |
2495 | minires_ninit (&resolver_state); | |
2496 | resolver_inited = 1; | |
2c46528f TL |
2497 | resolver_state.retrans = 1; |
2498 | resolver_state.retry = 1; | |
4bae15ec | 2499 | } |
7e799df1 | 2500 | ISC_LIST_INIT (uq); |
4bae15ec TL |
2501 | cur = expr; |
2502 | do { | |
2503 | next = cur -> data.dns_transaction.cdr; | |
2504 | nut = 0; | |
2505 | status = (evaluate_dns_expression | |
16121af5 TL |
2506 | (&nut, packet, |
2507 | lease, client_state, in_options, cfg_options, | |
4cbc378f | 2508 | scope, cur -> data.dns_transaction.car)); |
4bae15ec TL |
2509 | if (!status) |
2510 | goto dns_bad; | |
7e799df1 | 2511 | ISC_LIST_APPEND (uq, nut, r_link); |
4bae15ec TL |
2512 | cur = next; |
2513 | } while (next); | |
2514 | ||
2e236508 TL |
2515 | /* Do the update and record the error code, if there was |
2516 | an error; otherwise set it to NOERROR. */ | |
7167c654 TL |
2517 | *result = minires_nupdate (&resolver_state, |
2518 | ISC_LIST_HEAD (uq)); | |
4bae15ec TL |
2519 | status = 1; |
2520 | ||
2e236508 TL |
2521 | print_dns_status ((int)*result, &uq); |
2522 | ||
4bae15ec | 2523 | dns_bad: |
7e799df1 TL |
2524 | while (!ISC_LIST_EMPTY (uq)) { |
2525 | ns_updrec *tmp = ISC_LIST_HEAD (uq); | |
2526 | ISC_LIST_UNLINK (uq, tmp, r_link); | |
79c36eb7 TL |
2527 | if (tmp -> r_data_ephem) { |
2528 | dfree (tmp -> r_data_ephem, MDL); | |
9458e9aa | 2529 | tmp -> r_data = (unsigned char *)0; |
79c36eb7 | 2530 | tmp -> r_data_ephem = (unsigned char *)0; |
4cbc378f | 2531 | } |
88c32c8c | 2532 | minires_freeupdrec (tmp); |
4bae15ec TL |
2533 | } |
2534 | return status; | |
2535 | #endif /* NSUPDATE */ | |
2536 | ||
9f7050df | 2537 | case expr_variable_reference: |
6ceb9118 TL |
2538 | if (scope && *scope) { |
2539 | binding = find_binding (*scope, expr -> data.variable); | |
9f7050df | 2540 | |
6ceb9118 | 2541 | if (binding && binding -> value) { |
9f7050df TL |
2542 | if (binding -> value -> type == binding_numeric) { |
2543 | *result = binding -> value -> value.intval; | |
2544 | status = 1; | |
2545 | } else { | |
2546 | log_error ("binding type %d in %s.", | |
2547 | binding -> value -> type, | |
2548 | "evaluate_numeric_expression"); | |
2549 | status = 0; | |
2550 | } | |
6ceb9118 | 2551 | } else |
9f7050df | 2552 | status = 0; |
6ceb9118 TL |
2553 | } else |
2554 | status = 0; | |
9f7050df | 2555 | #if defined (DEBUG_EXPRESSIONS) |
16121af5 TL |
2556 | if (status) |
2557 | log_debug ("numeric: %s = %ld", | |
2558 | expr -> data.variable, *result); | |
2559 | else | |
2560 | log_debug ("numeric: %s = NULL", | |
2561 | expr -> data.variable); | |
9f7050df TL |
2562 | #endif |
2563 | return status; | |
2564 | ||
2565 | case expr_funcall: | |
2566 | bv = (struct binding_value *)0; | |
2567 | status = evaluate_expression (&bv, packet, lease, | |
16121af5 | 2568 | client_state, |
800f0de7 | 2569 | in_options, cfg_options, |
d758ad8c | 2570 | scope, expr, MDL); |
9f7050df TL |
2571 | if (status) { |
2572 | if (bv -> type != binding_numeric) | |
2573 | log_error ("%s() returned type %d in %s.", | |
2574 | expr -> data.funcall.name, | |
2575 | bv -> type, | |
2576 | "evaluate_numeric_expression"); | |
2577 | else | |
2578 | *result = bv -> value.intval; | |
2579 | binding_value_dereference (&bv, MDL); | |
2580 | } | |
2581 | #if defined (DEBUG_EXPRESSIONS) | |
16121af5 | 2582 | log_debug ("data: %s = %ld", expr -> data.funcall.name, |
9f7050df TL |
2583 | status ? *result : 0); |
2584 | #endif | |
2585 | break; | |
2586 | ||
800f0de7 TL |
2587 | case expr_add: |
2588 | sleft = evaluate_numeric_expression (&ileft, packet, lease, | |
16121af5 | 2589 | client_state, |
800f0de7 TL |
2590 | in_options, cfg_options, |
2591 | scope, | |
2592 | expr -> data.and [0]); | |
2593 | sright = evaluate_numeric_expression (&iright, packet, lease, | |
16121af5 | 2594 | client_state, |
800f0de7 TL |
2595 | in_options, cfg_options, |
2596 | scope, | |
2597 | expr -> data.and [1]); | |
2598 | ||
2599 | #if defined (DEBUG_EXPRESSIONS) | |
16121af5 TL |
2600 | if (sleft && sright) |
2601 | log_debug ("num: %ld + %ld = %ld", | |
2602 | ileft, iright, ileft + iright); | |
2603 | else if (sleft) | |
2604 | log_debug ("num: %ld + NULL = NULL", ileft); | |
2605 | else | |
2606 | log_debug ("num: NULL + %ld = NULL", iright); | |
800f0de7 TL |
2607 | #endif |
2608 | if (sleft && sright) { | |
2609 | *result = ileft + iright; | |
2610 | return 1; | |
2611 | } | |
2612 | return 0; | |
2613 | ||
2614 | case expr_subtract: | |
2615 | sleft = evaluate_numeric_expression (&ileft, packet, lease, | |
16121af5 | 2616 | client_state, |
800f0de7 TL |
2617 | in_options, cfg_options, |
2618 | scope, | |
2619 | expr -> data.and [0]); | |
2620 | sright = evaluate_numeric_expression (&iright, packet, lease, | |
16121af5 | 2621 | client_state, |
800f0de7 TL |
2622 | in_options, cfg_options, |
2623 | scope, | |
2624 | expr -> data.and [1]); | |
2625 | ||
2626 | #if defined (DEBUG_EXPRESSIONS) | |
16121af5 TL |
2627 | if (sleft && sright) |
2628 | log_debug ("num: %ld - %ld = %ld", | |
2629 | ileft, iright, ileft - iright); | |
2630 | else if (sleft) | |
2631 | log_debug ("num: %ld - NULL = NULL", ileft); | |
2632 | else | |
2633 | log_debug ("num: NULL - %ld = NULL", iright); | |
800f0de7 TL |
2634 | #endif |
2635 | if (sleft && sright) { | |
2636 | *result = ileft - iright; | |
2637 | return 1; | |
2638 | } | |
2639 | return 0; | |
2640 | ||
2641 | case expr_multiply: | |
2642 | sleft = evaluate_numeric_expression (&ileft, packet, lease, | |
16121af5 | 2643 | client_state, |
800f0de7 TL |
2644 | in_options, cfg_options, |
2645 | scope, | |
2646 | expr -> data.and [0]); | |
2647 | sright = evaluate_numeric_expression (&iright, packet, lease, | |
16121af5 | 2648 | client_state, |
800f0de7 TL |
2649 | in_options, cfg_options, |
2650 | scope, | |
2651 | expr -> data.and [1]); | |
2652 | ||
2653 | #if defined (DEBUG_EXPRESSIONS) | |
16121af5 TL |
2654 | if (sleft && sright) |
2655 | log_debug ("num: %ld * %ld = %ld", | |
2656 | ileft, iright, ileft * iright); | |
2657 | else if (sleft) | |
2658 | log_debug ("num: %ld * NULL = NULL", ileft); | |
2659 | else | |
2660 | log_debug ("num: NULL * %ld = NULL", iright); | |
800f0de7 TL |
2661 | #endif |
2662 | if (sleft && sright) { | |
2663 | *result = ileft * iright; | |
2664 | return 1; | |
2665 | } | |
2666 | return 0; | |
2667 | ||
2668 | case expr_divide: | |
2669 | sleft = evaluate_numeric_expression (&ileft, packet, lease, | |
16121af5 | 2670 | client_state, |
800f0de7 TL |
2671 | in_options, cfg_options, |
2672 | scope, | |
2673 | expr -> data.and [0]); | |
2674 | sright = evaluate_numeric_expression (&iright, packet, lease, | |
16121af5 | 2675 | client_state, |
800f0de7 TL |
2676 | in_options, cfg_options, |
2677 | scope, | |
2678 | expr -> data.and [1]); | |
2679 | ||
2680 | #if defined (DEBUG_EXPRESSIONS) | |
16121af5 TL |
2681 | if (sleft && sright) { |
2682 | if (iright != 0) | |
2683 | log_debug ("num: %ld / %ld = %ld", | |
2684 | ileft, iright, ileft / iright); | |
2685 | else | |
2686 | log_debug ("num: %ld / %ld = NULL", | |
2687 | ileft, iright); | |
2688 | } else if (sleft) | |
2689 | log_debug ("num: %ld / NULL = NULL", ileft); | |
2690 | else | |
2691 | log_debug ("num: NULL / %ld = NULL", iright); | |
800f0de7 TL |
2692 | #endif |
2693 | if (sleft && sright && iright) { | |
2694 | *result = ileft / iright; | |
2695 | return 1; | |
2696 | } | |
2697 | return 0; | |
2698 | ||
2699 | case expr_remainder: | |
2700 | sleft = evaluate_numeric_expression (&ileft, packet, lease, | |
16121af5 | 2701 | client_state, |
800f0de7 TL |
2702 | in_options, cfg_options, |
2703 | scope, | |
2704 | expr -> data.and [0]); | |
2705 | sright = evaluate_numeric_expression (&iright, packet, lease, | |
16121af5 | 2706 | client_state, |
800f0de7 TL |
2707 | in_options, cfg_options, |
2708 | scope, | |
2709 | expr -> data.and [1]); | |
2710 | ||
2711 | #if defined (DEBUG_EXPRESSIONS) | |
16121af5 TL |
2712 | if (sleft && sright) { |
2713 | if (iright != 0) | |
2714 | log_debug ("num: %ld %% %ld = %ld", | |
2715 | ileft, iright, ileft % iright); | |
2716 | else | |
2717 | log_debug ("num: %ld %% %ld = NULL", | |
2718 | ileft, iright); | |
2719 | } else if (sleft) | |
2720 | log_debug ("num: %ld %% NULL = NULL", ileft); | |
2721 | else | |
2722 | log_debug ("num: NULL %% %ld = NULL", iright); | |
800f0de7 TL |
2723 | #endif |
2724 | if (sleft && sright && iright) { | |
2725 | *result = ileft % iright; | |
2726 | return 1; | |
2727 | } | |
2728 | return 0; | |
2729 | ||
3c98e80b DN |
2730 | case expr_binary_and: |
2731 | sleft = evaluate_numeric_expression (&ileft, packet, lease, | |
16121af5 | 2732 | client_state, |
3c98e80b DN |
2733 | in_options, cfg_options, |
2734 | scope, | |
2735 | expr -> data.and [0]); | |
2736 | sright = evaluate_numeric_expression (&iright, packet, lease, | |
16121af5 | 2737 | client_state, |
3c98e80b DN |
2738 | in_options, cfg_options, |
2739 | scope, | |
2740 | expr -> data.and [1]); | |
2741 | ||
2742 | #if defined (DEBUG_EXPRESSIONS) | |
16121af5 TL |
2743 | if (sleft && sright) |
2744 | log_debug ("num: %ld | %ld = %ld", | |
2745 | ileft, iright, ileft & iright); | |
2746 | else if (sleft) | |
2747 | log_debug ("num: %ld & NULL = NULL", ileft); | |
2748 | else | |
2749 | log_debug ("num: NULL & %ld = NULL", iright); | |
3c98e80b DN |
2750 | #endif |
2751 | if (sleft && sright) { | |
2752 | *result = ileft & iright; | |
2753 | return 1; | |
2754 | } | |
2755 | return 0; | |
2756 | ||
2757 | case expr_binary_or: | |
2758 | sleft = evaluate_numeric_expression (&ileft, packet, lease, | |
16121af5 | 2759 | client_state, |
3c98e80b DN |
2760 | in_options, cfg_options, |
2761 | scope, | |
2762 | expr -> data.and [0]); | |
2763 | sright = evaluate_numeric_expression (&iright, packet, lease, | |
16121af5 | 2764 | client_state, |
3c98e80b DN |
2765 | in_options, cfg_options, |
2766 | scope, | |
2767 | expr -> data.and [1]); | |
2768 | ||
2769 | #if defined (DEBUG_EXPRESSIONS) | |
16121af5 TL |
2770 | if (sleft && sright) |
2771 | log_debug ("num: %ld | %ld = %ld", | |
2772 | ileft, iright, ileft | iright); | |
2773 | else if (sleft) | |
2774 | log_debug ("num: %ld | NULL = NULL", ileft); | |
2775 | else | |
2776 | log_debug ("num: NULL | %ld = NULL", iright); | |
3c98e80b DN |
2777 | #endif |
2778 | if (sleft && sright) { | |
2779 | *result = ileft | iright; | |
2780 | return 1; | |
2781 | } | |
2782 | return 0; | |
2783 | ||
2784 | case expr_binary_xor: | |
2785 | sleft = evaluate_numeric_expression (&ileft, packet, lease, | |
16121af5 | 2786 | client_state, |
3c98e80b DN |
2787 | in_options, cfg_options, |
2788 | scope, | |
2789 | expr -> data.and [0]); | |
2790 | sright = evaluate_numeric_expression (&iright, packet, lease, | |
16121af5 | 2791 | client_state, |
3c98e80b DN |
2792 | in_options, cfg_options, |
2793 | scope, | |
2794 | expr -> data.and [1]); | |
2795 | ||
2796 | #if defined (DEBUG_EXPRESSIONS) | |
16121af5 TL |
2797 | if (sleft && sright) |
2798 | log_debug ("num: %ld ^ %ld = %ld", | |
2799 | ileft, iright, ileft ^ iright); | |
2800 | else if (sleft) | |
2801 | log_debug ("num: %ld ^ NULL = NULL", ileft); | |
2802 | else | |
2803 | log_debug ("num: NULL ^ %ld = NULL", iright); | |
3c98e80b DN |
2804 | #endif |
2805 | if (sleft && sright) { | |
2806 | *result = ileft ^ iright; | |
2807 | return 1; | |
2808 | } | |
2809 | return 0; | |
2810 | ||
16121af5 TL |
2811 | case expr_client_state: |
2812 | if (client_state) { | |
2813 | #if defined (DEBUG_EXPRESSIONS) | |
2814 | log_debug ("num: client-state = %d", | |
2815 | client_state -> state); | |
2816 | #endif | |
2817 | *result = client_state -> state; | |
2818 | return 1; | |
2819 | } else { | |
2820 | #if defined (DEBUG_EXPRESSIONS) | |
2821 | log_debug ("num: client-state = NULL"); | |
2822 | #endif | |
2823 | return 0; | |
2824 | } | |
2825 | ||
2e236508 | 2826 | case expr_ns_add: |
4bae15ec TL |
2827 | case expr_ns_delete: |
2828 | case expr_ns_exists: | |
2829 | case expr_ns_not_exists: | |
2830 | log_error ("dns opcode in evaluate_numeric_expression: %d", | |
2831 | expr -> op); | |
2832 | return 0; | |
9f7050df | 2833 | |
800f0de7 TL |
2834 | case expr_function: |
2835 | log_error ("function definition in evaluate_numeric_expr"); | |
2836 | return 0; | |
2837 | ||
9f7050df TL |
2838 | case expr_arg: |
2839 | break; | |
b543fea9 DH |
2840 | |
2841 | default: | |
2842 | log_fatal("Impossible case at %s:%d. Undefined operator " | |
2843 | "%d.", MDL, expr->op); | |
2844 | break; | |
33e712ea TL |
2845 | } |
2846 | ||
10da3e76 | 2847 | log_error ("evaluate_numeric_expression: bogus opcode %d", expr -> op); |
33e712ea TL |
2848 | return 0; |
2849 | } | |
2850 | ||
1d07a807 TL |
2851 | /* Return data hanging off of an option cache structure, or if there |
2852 | isn't any, evaluate the expression hanging off of it and return the | |
2853 | result of that evaluation. There should never be both an expression | |
2854 | and a valid data_string. */ | |
2855 | ||
16121af5 | 2856 | int evaluate_option_cache (result, packet, lease, client_state, |
4cbc378f | 2857 | in_options, cfg_options, scope, oc, file, line) |
1d07a807 TL |
2858 | struct data_string *result; |
2859 | struct packet *packet; | |
da38df14 | 2860 | struct lease *lease; |
16121af5 | 2861 | struct client_state *client_state; |
4038ec52 TL |
2862 | struct option_state *in_options; |
2863 | struct option_state *cfg_options; | |
6ceb9118 | 2864 | struct binding_scope **scope; |
1d07a807 | 2865 | struct option_cache *oc; |
4cbc378f TL |
2866 | const char *file; |
2867 | int line; | |
1d07a807 | 2868 | { |
98bd7ca0 | 2869 | if (oc->data.data != NULL) { |
4cbc378f | 2870 | data_string_copy (result, &oc -> data, file, line); |
1d07a807 TL |
2871 | return 1; |
2872 | } | |
4766ef10 TL |
2873 | if (!oc -> expression) |
2874 | return 0; | |
16121af5 | 2875 | return evaluate_data_expression (result, packet, lease, client_state, |
4cbc378f | 2876 | in_options, cfg_options, scope, |
d758ad8c | 2877 | oc -> expression, file, line); |
1d07a807 TL |
2878 | } |
2879 | ||
2880 | /* Evaluate an option cache and extract a boolean from the result, | |
2881 | returning the boolean. Return false if there is no data. */ | |
2882 | ||
16121af5 TL |
2883 | int evaluate_boolean_option_cache (ignorep, packet, |
2884 | lease, client_state, in_options, | |
4cbc378f | 2885 | cfg_options, scope, oc, file, line) |
cc5bd211 | 2886 | int *ignorep; |
1d07a807 | 2887 | struct packet *packet; |
da38df14 | 2888 | struct lease *lease; |
16121af5 | 2889 | struct client_state *client_state; |
4038ec52 TL |
2890 | struct option_state *in_options; |
2891 | struct option_state *cfg_options; | |
6ceb9118 | 2892 | struct binding_scope **scope; |
33e712ea | 2893 | struct option_cache *oc; |
4cbc378f TL |
2894 | const char *file; |
2895 | int line; | |
33e712ea | 2896 | { |
1d07a807 TL |
2897 | struct data_string ds; |
2898 | int result; | |
2899 | ||
2900 | /* So that we can be called with option_lookup as an argument. */ | |
4038ec52 | 2901 | if (!oc || !in_options) |
1d07a807 TL |
2902 | return 0; |
2903 | ||
2904 | memset (&ds, 0, sizeof ds); | |
16121af5 TL |
2905 | if (!evaluate_option_cache (&ds, packet, |
2906 | lease, client_state, in_options, | |
4bd8800e | 2907 | cfg_options, scope, oc, file, line)) |
1d07a807 TL |
2908 | return 0; |
2909 | ||
cc5bd211 TL |
2910 | if (ds.len) { |
2911 | result = ds.data [0]; | |
2912 | if (result == 2) { | |
2913 | result = 0; | |
2914 | *ignorep = 1; | |
2915 | } else | |
2916 | *ignorep = 0; | |
2917 | } else | |
76a8f163 TL |
2918 | result = 0; |
2919 | data_string_forget (&ds, MDL); | |
1d07a807 | 2920 | return result; |
33e712ea | 2921 | } |
1d07a807 | 2922 | |
33e712ea | 2923 | |
1d07a807 TL |
2924 | /* Evaluate a boolean expression and return the result of the evaluation, |
2925 | or FALSE if it failed. */ | |
33e712ea | 2926 | |
16121af5 TL |
2927 | int evaluate_boolean_expression_result (ignorep, packet, lease, client_state, |
2928 | in_options, cfg_options, scope, expr) | |
cc5bd211 | 2929 | int *ignorep; |
1d07a807 | 2930 | struct packet *packet; |
da38df14 | 2931 | struct lease *lease; |
16121af5 | 2932 | struct client_state *client_state; |
4038ec52 TL |
2933 | struct option_state *in_options; |
2934 | struct option_state *cfg_options; | |
6ceb9118 | 2935 | struct binding_scope **scope; |
33e712ea TL |
2936 | struct expression *expr; |
2937 | { | |
1d07a807 TL |
2938 | int result; |
2939 | ||
2940 | /* So that we can be called with option_lookup as an argument. */ | |
2941 | if (!expr) | |
2942 | return 0; | |
2943 | ||
16121af5 | 2944 | if (!evaluate_boolean_expression (&result, packet, lease, client_state, |
4cbc378f | 2945 | in_options, cfg_options, |
4bd8800e | 2946 | scope, expr)) |
33e712ea TL |
2947 | return 0; |
2948 | ||
cc5bd211 TL |
2949 | if (result == 2) { |
2950 | *ignorep = 1; | |
2951 | result = 0; | |
2952 | } else | |
2953 | *ignorep = 0; | |
1d07a807 TL |
2954 | return result; |
2955 | } | |
2956 | ||
2957 | ||
2958 | /* Dereference an expression node, and if the reference count goes to zero, | |
2959 | dereference any data it refers to, and then free it. */ | |
4bd8800e | 2960 | void expression_dereference (eptr, file, line) |
1d07a807 | 2961 | struct expression **eptr; |
4bd8800e TL |
2962 | const char *file; |
2963 | int line; | |
1d07a807 TL |
2964 | { |
2965 | struct expression *expr = *eptr; | |
2966 | ||
2967 | /* Zero the pointer. */ | |
2968 | *eptr = (struct expression *)0; | |
2969 | ||
2970 | /* Decrement the reference count. If it's nonzero, we're | |
2971 | done. */ | |
4cbc378f | 2972 | --(expr -> refcnt); |
98311e4b | 2973 | rc_register (file, line, eptr, expr, expr -> refcnt, 1, RC_MISC); |
4cbc378f | 2974 | if (expr -> refcnt > 0) |
1d07a807 TL |
2975 | return; |
2976 | if (expr -> refcnt < 0) { | |
4bd8800e | 2977 | log_error ("%s(%d): negative refcnt!", file, line); |
4cbc378f | 2978 | #if defined (DEBUG_RC_HISTORY) |
d758ad8c | 2979 | dump_rc_history (expr); |
4cbc378f | 2980 | #endif |
10da3e76 | 2981 | #if defined (POINTER_DEBUG) |
1d07a807 | 2982 | abort (); |
10da3e76 TL |
2983 | #else |
2984 | return; | |
2985 | #endif | |
1d07a807 TL |
2986 | } |
2987 | ||
2988 | /* Dereference subexpressions. */ | |
33e712ea TL |
2989 | switch (expr -> op) { |
2990 | /* All the binary operators can be handled the same way. */ | |
2991 | case expr_equal: | |
2b965a44 | 2992 | case expr_not_equal: |
33e712ea TL |
2993 | case expr_concat: |
2994 | case expr_and: | |
2995 | case expr_or: | |
800f0de7 TL |
2996 | case expr_add: |
2997 | case expr_subtract: | |
2998 | case expr_multiply: | |
2999 | case expr_divide: | |
3000 | case expr_remainder: | |
3c98e80b DN |
3001 | case expr_binary_and: |
3002 | case expr_binary_or: | |
3003 | case expr_binary_xor: | |
16121af5 | 3004 | case expr_client_state: |
1d07a807 | 3005 | if (expr -> data.equal [0]) |
4bd8800e TL |
3006 | expression_dereference (&expr -> data.equal [0], |
3007 | file, line); | |
1d07a807 | 3008 | if (expr -> data.equal [1]) |
4bd8800e TL |
3009 | expression_dereference (&expr -> data.equal [1], |
3010 | file, line); | |
33e712ea TL |
3011 | break; |
3012 | ||
3013 | case expr_substring: | |
1d07a807 TL |
3014 | if (expr -> data.substring.expr) |
3015 | expression_dereference (&expr -> data.substring.expr, | |
4bd8800e | 3016 | file, line); |
1d07a807 TL |
3017 | if (expr -> data.substring.offset) |
3018 | expression_dereference (&expr -> data.substring.offset, | |
4bd8800e | 3019 | file, line); |
1d07a807 TL |
3020 | if (expr -> data.substring.len) |
3021 | expression_dereference (&expr -> data.substring.len, | |
4bd8800e | 3022 | file, line); |
33e712ea TL |
3023 | break; |
3024 | ||
3025 | case expr_suffix: | |
1d07a807 TL |
3026 | if (expr -> data.suffix.expr) |
3027 | expression_dereference (&expr -> data.suffix.expr, | |
4bd8800e | 3028 | file, line); |
1d07a807 TL |
3029 | if (expr -> data.suffix.len) |
3030 | expression_dereference (&expr -> data.suffix.len, | |
4bd8800e | 3031 | file, line); |
33e712ea TL |
3032 | break; |
3033 | ||
2727c1cf DH |
3034 | case expr_lcase: |
3035 | if (expr->data.lcase) | |
3036 | expression_dereference(&expr->data.lcase, MDL); | |
3037 | break; | |
3038 | ||
3039 | case expr_ucase: | |
3040 | if (expr->data.ucase) | |
3041 | expression_dereference(&expr->data.ucase, MDL); | |
3042 | break; | |
3043 | ||
33e712ea | 3044 | case expr_not: |
1d07a807 | 3045 | if (expr -> data.not) |
4bd8800e | 3046 | expression_dereference (&expr -> data.not, file, line); |
33e712ea TL |
3047 | break; |
3048 | ||
3049 | case expr_packet: | |
1d07a807 TL |
3050 | if (expr -> data.packet.offset) |
3051 | expression_dereference (&expr -> data.packet.offset, | |
4bd8800e | 3052 | file, line); |
1d07a807 TL |
3053 | if (expr -> data.packet.len) |
3054 | expression_dereference (&expr -> data.packet.len, | |
4bd8800e | 3055 | file, line); |
33e712ea TL |
3056 | break; |
3057 | ||
3058 | case expr_extract_int8: | |
3059 | case expr_extract_int16: | |
3060 | case expr_extract_int32: | |
1d07a807 TL |
3061 | if (expr -> data.extract_int) |
3062 | expression_dereference (&expr -> data.extract_int, | |
4bd8800e | 3063 | file, line); |
1d07a807 TL |
3064 | break; |
3065 | ||
20a767d3 TL |
3066 | case expr_encode_int8: |
3067 | case expr_encode_int16: | |
3068 | case expr_encode_int32: | |
3069 | if (expr -> data.encode_int) | |
3070 | expression_dereference (&expr -> data.encode_int, | |
4bd8800e | 3071 | file, line); |
20a767d3 TL |
3072 | break; |
3073 | ||
dd6e44a5 | 3074 | case expr_encapsulate: |
1d07a807 | 3075 | case expr_const_data: |
4bd8800e | 3076 | data_string_forget (&expr -> data.const_data, file, line); |
1d07a807 TL |
3077 | break; |
3078 | ||
3079 | case expr_host_lookup: | |
3080 | if (expr -> data.host_lookup) | |
3081 | dns_host_entry_dereference (&expr -> data.host_lookup, | |
4bd8800e | 3082 | file, line); |
33e712ea TL |
3083 | break; |
3084 | ||
da38df14 TL |
3085 | case expr_binary_to_ascii: |
3086 | if (expr -> data.b2a.base) | |
4bd8800e TL |
3087 | expression_dereference (&expr -> data.b2a.base, |
3088 | file, line); | |
da38df14 | 3089 | if (expr -> data.b2a.width) |
4bd8800e TL |
3090 | expression_dereference (&expr -> data.b2a.width, |
3091 | file, line); | |
c57db45c SK |
3092 | if (expr -> data.b2a.separator) |
3093 | expression_dereference (&expr -> data.b2a.separator, | |
4bd8800e | 3094 | file, line); |
da38df14 TL |
3095 | if (expr -> data.b2a.buffer) |
3096 | expression_dereference (&expr -> data.b2a.buffer, | |
4bd8800e | 3097 | file, line); |
da38df14 TL |
3098 | break; |
3099 | ||
79a65726 TL |
3100 | case expr_pick_first_value: |
3101 | if (expr -> data.pick_first_value.car) | |
4bd8800e TL |
3102 | expression_dereference (&expr -> data.pick_first_value.car, |
3103 | file, line); | |
79a65726 | 3104 | if (expr -> data.pick_first_value.cdr) |
4bd8800e TL |
3105 | expression_dereference (&expr -> data.pick_first_value.cdr, |
3106 | file, line); | |
79a65726 TL |
3107 | break; |
3108 | ||
da38df14 TL |
3109 | case expr_reverse: |
3110 | if (expr -> data.reverse.width) | |
3111 | expression_dereference (&expr -> data.reverse.width, | |
4bd8800e | 3112 | file, line); |
da38df14 TL |
3113 | if (expr -> data.reverse.buffer) |
3114 | expression_dereference | |
4bd8800e | 3115 | (&expr -> data.reverse.buffer, file, line); |
da38df14 TL |
3116 | break; |
3117 | ||
4bae15ec TL |
3118 | case expr_dns_transaction: |
3119 | if (expr -> data.dns_transaction.car) | |
4bd8800e TL |
3120 | expression_dereference (&expr -> data.dns_transaction.car, |
3121 | file, line); | |
4bae15ec | 3122 | if (expr -> data.dns_transaction.cdr) |
4bd8800e TL |
3123 | expression_dereference (&expr -> data.dns_transaction.cdr, |
3124 | file, line); | |
4bae15ec TL |
3125 | break; |
3126 | ||
2e236508 TL |
3127 | case expr_ns_add: |
3128 | if (expr -> data.ns_add.rrname) | |
3129 | expression_dereference (&expr -> data.ns_add.rrname, | |
4bd8800e | 3130 | file, line); |
2e236508 TL |
3131 | if (expr -> data.ns_add.rrdata) |
3132 | expression_dereference (&expr -> data.ns_add.rrdata, | |
4bd8800e | 3133 | file, line); |
2e236508 TL |
3134 | if (expr -> data.ns_add.ttl) |
3135 | expression_dereference (&expr -> data.ns_add.ttl, | |
4bd8800e | 3136 | file, line); |
4bae15ec TL |
3137 | break; |
3138 | ||
3139 | case expr_ns_delete: | |
3140 | case expr_ns_exists: | |
3141 | case expr_ns_not_exists: | |
3142 | if (expr -> data.ns_delete.rrname) | |
3143 | expression_dereference (&expr -> data.ns_delete.rrname, | |
4bd8800e | 3144 | file, line); |
4bae15ec TL |
3145 | if (expr -> data.ns_delete.rrdata) |
3146 | expression_dereference (&expr -> data.ns_delete.rrdata, | |
4bd8800e | 3147 | file, line); |
4bae15ec | 3148 | break; |
06a8567c | 3149 | |
2e236508 TL |
3150 | case expr_variable_reference: |
3151 | case expr_variable_exists: | |
3152 | if (expr -> data.variable) | |
4bd8800e | 3153 | dfree (expr -> data.variable, file, line); |
2e236508 TL |
3154 | break; |
3155 | ||
9f7050df TL |
3156 | case expr_funcall: |
3157 | if (expr -> data.funcall.name) | |
3158 | dfree (expr -> data.funcall.name, file, line); | |
3159 | if (expr -> data.funcall.arglist) | |
3160 | expression_dereference (&expr -> data.funcall.arglist, | |
3161 | file, line); | |
3162 | break; | |
3163 | ||
3164 | case expr_arg: | |
3165 | if (expr -> data.arg.val) | |
3166 | expression_dereference (&expr -> data.arg.val, | |
3167 | file, line); | |
3168 | if (expr -> data.arg.next) | |
3169 | expression_dereference (&expr -> data.arg.next, | |
3170 | file, line); | |
3171 | break; | |
3172 | ||
800f0de7 TL |
3173 | case expr_function: |
3174 | fundef_dereference (&expr -> data.func, file, line); | |
3175 | break; | |
3176 | ||
33e712ea | 3177 | /* No subexpressions. */ |
da38df14 | 3178 | case expr_leased_address: |
069e9f4c | 3179 | case expr_lease_time: |
4cbc378f TL |
3180 | case expr_filename: |
3181 | case expr_sname: | |
33e712ea TL |
3182 | case expr_const_int: |
3183 | case expr_check: | |
33e712ea | 3184 | case expr_option: |
33e712ea | 3185 | case expr_hardware: |
1d07a807 | 3186 | case expr_exists: |
5ce6b576 | 3187 | case expr_known: |
2e236508 | 3188 | case expr_null: |
33e712ea TL |
3189 | break; |
3190 | ||
3191 | default: | |
3192 | break; | |
3193 | } | |
4cbc378f | 3194 | free_expression (expr, MDL); |
1d07a807 TL |
3195 | } |
3196 | ||
4bae15ec TL |
3197 | int is_dns_expression (expr) |
3198 | struct expression *expr; | |
3199 | { | |
2e236508 | 3200 | return (expr -> op == expr_ns_add || |
4bae15ec TL |
3201 | expr -> op == expr_ns_delete || |
3202 | expr -> op == expr_ns_exists || | |
3203 | expr -> op == expr_ns_not_exists); | |
3204 | } | |
3205 | ||
1d07a807 TL |
3206 | int is_boolean_expression (expr) |
3207 | struct expression *expr; | |
3208 | { | |
3209 | return (expr -> op == expr_check || | |
10da3e76 | 3210 | expr -> op == expr_exists || |
2e236508 | 3211 | expr -> op == expr_variable_exists || |
1d07a807 | 3212 | expr -> op == expr_equal || |
2b965a44 | 3213 | expr -> op == expr_not_equal || |
1d07a807 TL |
3214 | expr -> op == expr_and || |
3215 | expr -> op == expr_or || | |
a8a20d8a | 3216 | expr -> op == expr_not || |
1c5d5731 TL |
3217 | expr -> op == expr_known || |
3218 | expr -> op == expr_static); | |
1d07a807 TL |
3219 | } |
3220 | ||
3221 | int is_data_expression (expr) | |
3222 | struct expression *expr; | |
3223 | { | |
2727c1cf DH |
3224 | return (expr->op == expr_substring || |
3225 | expr->op == expr_suffix || | |
3226 | expr->op == expr_lcase || | |
3227 | expr->op == expr_ucase || | |
3228 | expr->op == expr_option || | |
3229 | expr->op == expr_hardware || | |
3230 | expr->op == expr_const_data || | |
3231 | expr->op == expr_packet || | |
3232 | expr->op == expr_concat || | |
3233 | expr->op == expr_encapsulate || | |
3234 | expr->op == expr_encode_int8 || | |
3235 | expr->op == expr_encode_int16 || | |
3236 | expr->op == expr_encode_int32 || | |
3237 | expr->op == expr_host_lookup || | |
3238 | expr->op == expr_binary_to_ascii || | |
3239 | expr->op == expr_filename || | |
3240 | expr->op == expr_sname || | |
3241 | expr->op == expr_reverse || | |
3242 | expr->op == expr_pick_first_value || | |
3243 | expr->op == expr_host_decl_name || | |
3244 | expr->op == expr_leased_address || | |
3245 | expr->op == expr_config_option || | |
3246 | expr->op == expr_null); | |
1d07a807 TL |
3247 | } |
3248 | ||
3249 | int is_numeric_expression (expr) | |
3250 | struct expression *expr; | |
3251 | { | |
3252 | return (expr -> op == expr_extract_int8 || | |
3253 | expr -> op == expr_extract_int16 || | |
3254 | expr -> op == expr_extract_int32 || | |
cd31814f | 3255 | expr -> op == expr_const_int || |
4bae15ec | 3256 | expr -> op == expr_lease_time || |
0bcad761 TL |
3257 | expr -> op == expr_dns_transaction || |
3258 | expr -> op == expr_add || | |
3259 | expr -> op == expr_subtract || | |
3260 | expr -> op == expr_multiply || | |
3261 | expr -> op == expr_divide || | |
3c98e80b DN |
3262 | expr -> op == expr_remainder || |
3263 | expr -> op == expr_binary_and || | |
3264 | expr -> op == expr_binary_or || | |
16121af5 TL |
3265 | expr -> op == expr_binary_xor || |
3266 | expr -> op == expr_client_state); | |
1d07a807 TL |
3267 | } |
3268 | ||
2e236508 TL |
3269 | int is_compound_expression (expr) |
3270 | struct expression *expr; | |
3271 | { | |
3272 | return (expr -> op == expr_ns_add || | |
3273 | expr -> op == expr_ns_delete || | |
3274 | expr -> op == expr_ns_exists || | |
3275 | expr -> op == expr_ns_not_exists || | |
3276 | expr -> op == expr_substring || | |
3277 | expr -> op == expr_suffix || | |
3278 | expr -> op == expr_option || | |
3279 | expr -> op == expr_concat || | |
3280 | expr -> op == expr_encode_int8 || | |
3281 | expr -> op == expr_encode_int16 || | |
3282 | expr -> op == expr_encode_int32 || | |
3283 | expr -> op == expr_binary_to_ascii || | |
3284 | expr -> op == expr_reverse || | |
3285 | expr -> op == expr_pick_first_value || | |
3286 | expr -> op == expr_config_option || | |
3287 | expr -> op == expr_extract_int8 || | |
3288 | expr -> op == expr_extract_int16 || | |
3289 | expr -> op == expr_extract_int32 || | |
3290 | expr -> op == expr_dns_transaction); | |
3291 | } | |
3292 | ||
1d07a807 TL |
3293 | static int op_val PROTO ((enum expr_op)); |
3294 | ||
3295 | static int op_val (op) | |
3296 | enum expr_op op; | |
3297 | { | |
3298 | switch (op) { | |
3299 | case expr_none: | |
3300 | case expr_match: | |
1c5d5731 | 3301 | case expr_static: |
1d07a807 TL |
3302 | case expr_check: |
3303 | case expr_substring: | |
3304 | case expr_suffix: | |
2727c1cf DH |
3305 | case expr_lcase: |
3306 | case expr_ucase: | |
1d07a807 | 3307 | case expr_concat: |
dd6e44a5 | 3308 | case expr_encapsulate: |
1d07a807 TL |
3309 | case expr_host_lookup: |
3310 | case expr_not: | |
3311 | case expr_option: | |
3312 | case expr_hardware: | |
3313 | case expr_packet: | |
3314 | case expr_const_data: | |
3315 | case expr_extract_int8: | |
3316 | case expr_extract_int16: | |
3317 | case expr_extract_int32: | |
20a767d3 TL |
3318 | case expr_encode_int8: |
3319 | case expr_encode_int16: | |
3320 | case expr_encode_int32: | |
1d07a807 TL |
3321 | case expr_const_int: |
3322 | case expr_exists: | |
2e236508 | 3323 | case expr_variable_exists: |
5ce6b576 | 3324 | case expr_known: |
da38df14 TL |
3325 | case expr_binary_to_ascii: |
3326 | case expr_reverse: | |
4cbc378f TL |
3327 | case expr_filename: |
3328 | case expr_sname: | |
79a65726 TL |
3329 | case expr_pick_first_value: |
3330 | case expr_host_decl_name: | |
3331 | case expr_config_option: | |
da38df14 | 3332 | case expr_leased_address: |
cd31814f | 3333 | case expr_lease_time: |
4bae15ec | 3334 | case expr_dns_transaction: |
2e236508 TL |
3335 | case expr_null: |
3336 | case expr_variable_reference: | |
3337 | case expr_ns_add: | |
4bae15ec TL |
3338 | case expr_ns_delete: |
3339 | case expr_ns_exists: | |
3340 | case expr_ns_not_exists: | |
9f7050df TL |
3341 | case expr_arg: |
3342 | case expr_funcall: | |
800f0de7 | 3343 | case expr_function: |
3c98e80b DN |
3344 | /* XXXDPN: Need to assign sane precedences to these. */ |
3345 | case expr_binary_and: | |
3346 | case expr_binary_or: | |
3347 | case expr_binary_xor: | |
16121af5 | 3348 | case expr_client_state: |
1d07a807 TL |
3349 | return 100; |
3350 | ||
3351 | case expr_equal: | |
2b965a44 | 3352 | case expr_not_equal: |
98311e4b | 3353 | return 4; |
1d07a807 | 3354 | |
98311e4b | 3355 | case expr_or: |
1d07a807 | 3356 | case expr_and: |
98311e4b | 3357 | return 3; |
1d07a807 | 3358 | |
800f0de7 TL |
3359 | case expr_add: |
3360 | case expr_subtract: | |
1d07a807 | 3361 | return 2; |
98311e4b DH |
3362 | |
3363 | case expr_multiply: | |
3364 | case expr_divide: | |
3365 | case expr_remainder: | |
3366 | return 1; | |
1d07a807 TL |
3367 | } |
3368 | return 100; | |
3369 | } | |
3370 | ||
3371 | int op_precedence (op1, op2) | |
3372 | enum expr_op op1, op2; | |
3373 | { | |
3374 | int ov1, ov2; | |
3375 | ||
3376 | return op_val (op1) - op_val (op2); | |
3377 | } | |
3378 | ||
2c46528f TL |
3379 | enum expression_context expression_context (struct expression *expr) |
3380 | { | |
3381 | if (is_data_expression (expr)) | |
3382 | return context_data; | |
3383 | if (is_numeric_expression (expr)) | |
3384 | return context_numeric; | |
3385 | if (is_boolean_expression (expr)) | |
3386 | return context_boolean; | |
3387 | if (is_dns_expression (expr)) | |
3388 | return context_dns; | |
3389 | return context_any; | |
3390 | } | |
3391 | ||
1d07a807 TL |
3392 | enum expression_context op_context (op) |
3393 | enum expr_op op; | |
3394 | { | |
3395 | switch (op) { | |
da38df14 | 3396 | /* XXX Why aren't these specific? */ |
1d07a807 TL |
3397 | case expr_none: |
3398 | case expr_match: | |
1c5d5731 | 3399 | case expr_static: |
1d07a807 TL |
3400 | case expr_check: |
3401 | case expr_substring: | |
3402 | case expr_suffix: | |
2727c1cf DH |
3403 | case expr_lcase: |
3404 | case expr_ucase: | |
1d07a807 | 3405 | case expr_concat: |
dd6e44a5 | 3406 | case expr_encapsulate: |
1d07a807 TL |
3407 | case expr_host_lookup: |
3408 | case expr_not: | |
3409 | case expr_option: | |
3410 | case expr_hardware: | |
3411 | case expr_packet: | |
3412 | case expr_const_data: | |
3413 | case expr_extract_int8: | |
3414 | case expr_extract_int16: | |
3415 | case expr_extract_int32: | |
20a767d3 TL |
3416 | case expr_encode_int8: |
3417 | case expr_encode_int16: | |
3418 | case expr_encode_int32: | |
1d07a807 TL |
3419 | case expr_const_int: |
3420 | case expr_exists: | |
2e236508 | 3421 | case expr_variable_exists: |
5ce6b576 | 3422 | case expr_known: |
da38df14 TL |
3423 | case expr_binary_to_ascii: |
3424 | case expr_reverse: | |
4cbc378f TL |
3425 | case expr_filename: |
3426 | case expr_sname: | |
79a65726 TL |
3427 | case expr_pick_first_value: |
3428 | case expr_host_decl_name: | |
3429 | case expr_config_option: | |
da38df14 | 3430 | case expr_leased_address: |
cd31814f | 3431 | case expr_lease_time: |
2e236508 TL |
3432 | case expr_null: |
3433 | case expr_variable_reference: | |
3434 | case expr_ns_add: | |
4bae15ec TL |
3435 | case expr_ns_delete: |
3436 | case expr_ns_exists: | |
3437 | case expr_ns_not_exists: | |
3438 | case expr_dns_transaction: | |
9f7050df TL |
3439 | case expr_arg: |
3440 | case expr_funcall: | |
800f0de7 | 3441 | case expr_function: |
1d07a807 TL |
3442 | return context_any; |
3443 | ||
3444 | case expr_equal: | |
2b965a44 | 3445 | case expr_not_equal: |
1d07a807 TL |
3446 | return context_data; |
3447 | ||
3448 | case expr_and: | |
3449 | return context_boolean; | |
3450 | ||
3451 | case expr_or: | |
3452 | return context_boolean; | |
800f0de7 TL |
3453 | |
3454 | case expr_add: | |
3455 | case expr_subtract: | |
3456 | case expr_multiply: | |
3457 | case expr_divide: | |
3458 | case expr_remainder: | |
3c98e80b DN |
3459 | case expr_binary_and: |
3460 | case expr_binary_or: | |
3461 | case expr_binary_xor: | |
16121af5 | 3462 | case expr_client_state: |
800f0de7 | 3463 | return context_numeric; |
1d07a807 TL |
3464 | } |
3465 | return context_any; | |
3466 | } | |
fa098be8 | 3467 | |
2e236508 | 3468 | int write_expression (file, expr, col, indent, firstp) |
fa098be8 TL |
3469 | FILE *file; |
3470 | struct expression *expr; | |
3471 | int col; | |
3472 | int indent; | |
2e236508 | 3473 | int firstp; |
fa098be8 TL |
3474 | { |
3475 | struct expression *e; | |
b543fea9 | 3476 | struct expression *next_arg; |
b1b7b521 | 3477 | const char *s; |
fa098be8 TL |
3478 | char obuf [65]; |
3479 | int scol; | |
3480 | int width; | |
3481 | ||
2e236508 TL |
3482 | /* If this promises to be a fat expression, start a new line. */ |
3483 | if (!firstp && is_compound_expression (expr)) { | |
3484 | indent_spaces (file, indent); | |
3485 | col = indent; | |
3486 | } | |
3487 | ||
fa098be8 TL |
3488 | switch (expr -> op) { |
3489 | case expr_none: | |
3490 | col = token_print_indent (file, col, indent, "", "", "null"); | |
3491 | break; | |
3492 | ||
3493 | case expr_check: | |
3494 | col = token_print_indent (file, col, indent, "", "", "check"); | |
3495 | col = token_print_indent_concat (file, col, indent, | |
3496 | " ", "", "\"", | |
3497 | expr -> data.check -> name, | |
3498 | "\"", (char *)0); | |
3499 | break; | |
3500 | ||
2b965a44 TL |
3501 | case expr_not_equal: |
3502 | s = "!="; | |
3503 | goto binary; | |
3504 | ||
fa098be8 TL |
3505 | case expr_equal: |
3506 | s = "="; | |
3507 | binary: | |
2e236508 TL |
3508 | col = write_expression (file, expr -> data.equal [0], |
3509 | col, indent, 1); | |
fa098be8 | 3510 | col = token_print_indent (file, col, indent, " ", " ", s); |
2e236508 TL |
3511 | col = write_expression (file, expr -> data.equal [1], |
3512 | col, indent + 2, 0); | |
fa098be8 TL |
3513 | break; |
3514 | ||
3515 | case expr_substring: | |
3516 | col = token_print_indent (file, col, indent, "", "", | |
3517 | "substring"); | |
3518 | col = token_print_indent (file, col, indent, " ", "", "("); | |
3519 | scol = col; | |
3520 | col = write_expression (file, expr -> data.substring.expr, | |
2e236508 | 3521 | col, scol, 1); |
fa098be8 TL |
3522 | col = token_print_indent (file, col, indent, "", " ", ","); |
3523 | col = write_expression (file, expr -> data.substring.offset, | |
2e236508 | 3524 | col, indent, 0); |
fa098be8 TL |
3525 | col = token_print_indent (file, col, scol, "", " ", ","); |
3526 | col = write_expression (file, expr -> data.substring.len, | |
2e236508 | 3527 | col, scol, 0); |
fa098be8 TL |
3528 | col = token_print_indent (file, col, indent, "", "", ")"); |
3529 | break; | |
3530 | ||
3531 | case expr_suffix: | |
3532 | col = token_print_indent (file, col, indent, "", "", "suffix"); | |
3533 | col = token_print_indent (file, col, indent, " ", "", "("); | |
3534 | scol = col; | |
3535 | col = write_expression (file, expr -> data.suffix.expr, | |
2e236508 | 3536 | col, scol, 1); |
fa098be8 TL |
3537 | col = token_print_indent (file, col, scol, "", " ", ","); |
3538 | col = write_expression (file, expr -> data.suffix.len, | |
2e236508 | 3539 | col, scol, 0); |
fa098be8 | 3540 | col = token_print_indent (file, col, indent, "", "", ")"); |
2727c1cf DH |
3541 | |
3542 | case expr_lcase: | |
3543 | col = token_print_indent(file, col, indent, "", "", "lcase"); | |
3544 | col = token_print_indent(file, col, indent, " ", "", "("); | |
3545 | scol = col; | |
3546 | col = write_expression(file, expr->data.lcase, col, scol, 1); | |
3547 | col = token_print_indent(file, col, indent, "", "", ")"); | |
3548 | break; | |
3549 | ||
3550 | case expr_ucase: | |
3551 | col = token_print_indent(file, col, indent, "", "", "ucase"); | |
3552 | col = token_print_indent(file, col, indent, " ", "", "("); | |
3553 | scol = col; | |
3554 | col = write_expression(file, expr->data.ucase, col, scol, 1); | |
3555 | col = token_print_indent(file, col, indent, "", "", ")"); | |
fa098be8 TL |
3556 | break; |
3557 | ||
3558 | case expr_concat: | |
3559 | e = expr; | |
3560 | col = token_print_indent (file, col, indent, "", "", | |
3561 | "concat"); | |
3562 | col = token_print_indent (file, col, indent, " ", "", "("); | |
3563 | scol = col; | |
2e236508 | 3564 | firstp = 1; |
fa098be8 TL |
3565 | concat_again: |
3566 | col = write_expression (file, e -> data.concat [0], | |
2e236508 TL |
3567 | col, scol, firstp); |
3568 | firstp = 0; | |
e05e0b0b TL |
3569 | if (!e -> data.concat [1]) |
3570 | goto no_concat_cdr; | |
fa098be8 TL |
3571 | col = token_print_indent (file, col, scol, "", " ", ","); |
3572 | if (e -> data.concat [1] -> op == expr_concat) { | |
3573 | e = e -> data.concat [1]; | |
3574 | goto concat_again; | |
3575 | } | |
3576 | col = write_expression (file, e -> data.concat [1], | |
2e236508 | 3577 | col, scol, 0); |
e05e0b0b | 3578 | no_concat_cdr: |
fa098be8 TL |
3579 | col = token_print_indent (file, col, indent, "", "", ")"); |
3580 | break; | |
3581 | ||
3582 | case expr_host_lookup: | |
3583 | col = token_print_indent (file, col, indent, "", "", | |
3584 | "gethostbyname"); | |
3585 | col = token_print_indent (file, col, indent, " ", "", "("); | |
3586 | col = token_print_indent_concat | |
3587 | (file, col, indent, "", "", | |
3588 | "\"", expr -> data.host_lookup -> hostname, "\"", | |
3589 | (char *)0); | |
3590 | col = token_print_indent (file, col, indent, "", "", ")"); | |
3591 | break; | |
3592 | ||
800f0de7 TL |
3593 | case expr_add: |
3594 | s = "+"; | |
3595 | goto binary; | |
3596 | ||
3597 | case expr_subtract: | |
3598 | s = "-"; | |
3599 | goto binary; | |
3600 | ||
3601 | case expr_multiply: | |
3602 | s = "*"; | |
3603 | goto binary; | |
3604 | ||
3605 | case expr_divide: | |
3606 | s = "/"; | |
3607 | goto binary; | |
3608 | ||
3609 | case expr_remainder: | |
3610 | s = "%"; | |
3611 | goto binary; | |
3612 | ||
3c98e80b DN |
3613 | case expr_binary_and: |
3614 | s = "&"; | |
3615 | goto binary; | |
3616 | ||
3617 | case expr_binary_or: | |
3618 | s = "|"; | |
3619 | goto binary; | |
3620 | ||
3621 | case expr_binary_xor: | |
3622 | s = "^"; | |
3623 | goto binary; | |
3624 | ||
fa098be8 TL |
3625 | case expr_and: |
3626 | s = "and"; | |
3627 | goto binary; | |
3628 | ||
3629 | case expr_or: | |
3630 | s = "or"; | |
3631 | goto binary; | |
3632 | ||
3633 | case expr_not: | |
3634 | col = token_print_indent (file, col, indent, "", " ", "not"); | |
3635 | col = write_expression (file, | |
2e236508 | 3636 | expr -> data.not, col, indent + 2, 1); |
fa098be8 TL |
3637 | break; |
3638 | ||
3639 | case expr_option: | |
3640 | s = "option"; | |
3641 | ||
3642 | print_option_name: | |
3643 | col = token_print_indent (file, col, indent, "", "", s); | |
3644 | ||
3645 | if (expr -> data.option -> universe != &dhcp_universe) { | |
3646 | col = token_print_indent (file, col, indent, | |
3647 | " ", "", | |
3648 | (expr -> data.option -> | |
3649 | universe -> name)); | |
3650 | col = token_print_indent (file, col, indent, "", "", | |
3651 | "."); | |
3652 | col = token_print_indent (file, col, indent, "", "", | |
3653 | expr -> data.option -> name); | |
3654 | } else { | |
3655 | col = token_print_indent (file, col, indent, " ", "", | |
3656 | expr -> data.option -> name); | |
3657 | } | |
3658 | break; | |
3659 | ||
3660 | case expr_hardware: | |
3661 | col = token_print_indent (file, col, indent, "", "", | |
3662 | "hardware"); | |
3663 | break; | |
3664 | ||
3665 | case expr_packet: | |
3666 | col = token_print_indent (file, col, indent, "", "", | |
3667 | "packet"); | |
3668 | col = token_print_indent (file, col, indent, " ", "", "("); | |
3669 | scol = col; | |
3670 | col = write_expression (file, expr -> data.packet.offset, | |
2e236508 | 3671 | col, indent, 1); |
fa098be8 TL |
3672 | col = token_print_indent (file, col, scol, "", " ", ","); |
3673 | col = write_expression (file, expr -> data.packet.len, | |
2e236508 | 3674 | col, scol, 0); |
fa098be8 TL |
3675 | col = token_print_indent (file, col, indent, "", "", ")"); |
3676 | break; | |
3677 | ||
3678 | case expr_const_data: | |
3679 | col = token_indent_data_string (file, col, indent, "", "", | |
3680 | &expr -> data.const_data); | |
3681 | break; | |
3682 | ||
3683 | case expr_extract_int8: | |
3684 | width = 8; | |
3685 | extract_int: | |
3686 | col = token_print_indent (file, col, indent, "", "", | |
3687 | "extract-int"); | |
3688 | col = token_print_indent (file, col, indent, " ", "", "("); | |
3689 | scol = col; | |
3690 | col = write_expression (file, expr -> data.extract_int, | |
2e236508 | 3691 | col, indent, 1); |
fa098be8 TL |
3692 | col = token_print_indent (file, col, scol, "", " ", ","); |
3693 | sprintf (obuf, "%d", width); | |
3694 | col = token_print_indent (file, col, scol, " ", "", obuf); | |
3695 | col = token_print_indent (file, col, indent, "", "", ")"); | |
3696 | break; | |
3697 | ||
3698 | case expr_extract_int16: | |
3699 | width = 16; | |
3700 | goto extract_int; | |
3701 | ||
3702 | case expr_extract_int32: | |
3703 | width = 32; | |
3704 | goto extract_int; | |
3705 | ||
3706 | case expr_encode_int8: | |
3707 | width = 8; | |
3708 | encode_int: | |
3709 | col = token_print_indent (file, col, indent, "", "", | |
3710 | "encode-int"); | |
3711 | col = token_print_indent (file, col, indent, " ", "", "("); | |
3712 | scol = col; | |
3713 | col = write_expression (file, expr -> data.extract_int, | |
2e236508 | 3714 | col, indent, 1); |
fa098be8 TL |
3715 | col = token_print_indent (file, col, scol, "", " ", ","); |
3716 | sprintf (obuf, "%d", width); | |
3717 | col = token_print_indent (file, col, scol, " ", "", obuf); | |
3718 | col = token_print_indent (file, col, indent, "", "", | |
3719 | ")"); | |
3720 | break; | |
3721 | ||
3722 | case expr_encode_int16: | |
3723 | width = 16; | |
3724 | goto encode_int; | |
3725 | ||
3726 | case expr_encode_int32: | |
3727 | width = 32; | |
3728 | goto encode_int; | |
3729 | ||
3730 | case expr_const_int: | |
3731 | sprintf (obuf, "%lu", expr -> data.const_int); | |
3732 | col = token_print_indent (file, col, indent, "", "", obuf); | |
3733 | break; | |
3734 | ||
3735 | case expr_exists: | |
3736 | s = "exists"; | |
3737 | goto print_option_name; | |
3738 | ||
3739 | case expr_encapsulate: | |
3740 | col = token_print_indent (file, col, indent, "", "", | |
3741 | "encapsulate"); | |
3742 | col = token_indent_data_string (file, col, indent, " ", "", | |
3743 | &expr -> data.encapsulate); | |
3744 | break; | |
3745 | ||
3746 | case expr_known: | |
3747 | col = token_print_indent (file, col, indent, "", "", "known"); | |
3748 | break; | |
3749 | ||
3750 | case expr_reverse: | |
3751 | col = token_print_indent (file, col, indent, "", "", | |
3752 | "reverse"); | |
3753 | col = token_print_indent (file, col, indent, " ", "", "("); | |
3754 | scol = col; | |
3755 | col = write_expression (file, expr -> data.reverse.width, | |
2e236508 | 3756 | col, scol, 1); |
fa098be8 TL |
3757 | col = token_print_indent (file, col, scol, "", " ", ","); |
3758 | col = write_expression (file, expr -> data.reverse.buffer, | |
2e236508 | 3759 | col, scol, 0); |
fa098be8 TL |
3760 | col = token_print_indent (file, col, indent, "", "", |
3761 | ")"); | |
3762 | break; | |
3763 | ||
3764 | case expr_leased_address: | |
3765 | col = token_print_indent (file, col, indent, "", "", | |
3766 | "leased-address"); | |
3767 | break; | |
3768 | ||
16121af5 TL |
3769 | case expr_client_state: |
3770 | col = token_print_indent (file, col, indent, "", "", | |
3771 | "client-state"); | |
3772 | break; | |
3773 | ||
fa098be8 TL |
3774 | case expr_binary_to_ascii: |
3775 | col = token_print_indent (file, col, indent, "", "", | |
3776 | "binary-to-ascii"); | |
3777 | col = token_print_indent (file, col, indent, " ", "", | |
3778 | "("); | |
3779 | scol = col; | |
3780 | col = write_expression (file, expr -> data.b2a.base, | |
2e236508 | 3781 | col, scol, 1); |
fa098be8 TL |
3782 | col = token_print_indent (file, col, scol, "", " ", |
3783 | ","); | |
3784 | col = write_expression (file, expr -> data.b2a.width, | |
2e236508 | 3785 | col, scol, 0); |
fa098be8 TL |
3786 | col = token_print_indent (file, col, scol, "", " ", |
3787 | ","); | |
c57db45c | 3788 | col = write_expression (file, expr -> data.b2a.separator, |
2e236508 | 3789 | col, scol, 0); |
fa098be8 TL |
3790 | col = token_print_indent (file, col, scol, "", " ", |
3791 | ","); | |
3792 | col = write_expression (file, expr -> data.b2a.buffer, | |
2e236508 | 3793 | col, scol, 0); |
fa098be8 TL |
3794 | col = token_print_indent (file, col, indent, "", "", |
3795 | ")"); | |
3796 | break; | |
3797 | ||
3798 | case expr_config_option: | |
bb27c66f | 3799 | s = "config-option"; |
fa098be8 TL |
3800 | goto print_option_name; |
3801 | ||
3802 | case expr_host_decl_name: | |
3803 | col = token_print_indent (file, col, indent, "", "", | |
3804 | "host-decl-name"); | |
3805 | break; | |
3806 | ||
3807 | case expr_pick_first_value: | |
3808 | e = expr; | |
3809 | col = token_print_indent (file, col, indent, "", "", | |
3810 | "concat"); | |
3811 | col = token_print_indent (file, col, indent, " ", "", | |
3812 | "("); | |
3813 | scol = col; | |
2e236508 | 3814 | firstp = 1; |
fa098be8 TL |
3815 | pick_again: |
3816 | col = write_expression (file, | |
3817 | e -> data.pick_first_value.car, | |
2e236508 TL |
3818 | col, scol, firstp); |
3819 | firstp = 0; | |
e05e0b0b TL |
3820 | /* We're being very lisp-like right now - instead of |
3821 | representing this expression as (first middle . last) we're | |
3822 | representing it as (first middle last), which means that the | |
3823 | tail cdr is always nil. Apologies to non-wisp-lizards - may | |
3824 | this obscure way of describing the problem motivate you to | |
3825 | learn more about the one true computing language. */ | |
3826 | if (!e -> data.pick_first_value.cdr) | |
3827 | goto no_pick_cdr; | |
fa098be8 TL |
3828 | col = token_print_indent (file, col, scol, "", " ", |
3829 | ","); | |
3830 | if (e -> data.pick_first_value.cdr -> op == | |
3831 | expr_pick_first_value) { | |
3832 | e = e -> data.pick_first_value.cdr; | |
3833 | goto pick_again; | |
3834 | } | |
3835 | col = write_expression (file, | |
3836 | e -> data.pick_first_value.cdr, | |
2e236508 | 3837 | col, scol, 0); |
e05e0b0b | 3838 | no_pick_cdr: |
fa098be8 TL |
3839 | col = token_print_indent (file, col, indent, "", "", |
3840 | ")"); | |
3841 | break; | |
3842 | ||
3843 | case expr_lease_time: | |
3844 | col = token_print_indent (file, col, indent, "", "", | |
3845 | "lease-time"); | |
3846 | break; | |
3847 | ||
4bae15ec | 3848 | case expr_dns_transaction: |
fa098be8 | 3849 | col = token_print_indent (file, col, indent, "", "", |
2e236508 | 3850 | "ns-update"); |
fa098be8 TL |
3851 | col = token_print_indent (file, col, indent, " ", "", |
3852 | "("); | |
2e236508 | 3853 | scol = 0; |
4bae15ec TL |
3854 | for (e = expr; |
3855 | e && e -> op == expr_dns_transaction; | |
3856 | e = e -> data.dns_transaction.cdr) { | |
2e236508 TL |
3857 | if (!scol) { |
3858 | scol = col; | |
3859 | firstp = 1; | |
3860 | } else | |
3861 | firstp = 0; | |
4bae15ec TL |
3862 | col = write_expression (file, |
3863 | e -> data.dns_transaction.car, | |
2e236508 | 3864 | col, scol, firstp); |
4bae15ec TL |
3865 | if (e -> data.dns_transaction.cdr) |
3866 | col = token_print_indent (file, col, scol, | |
3867 | "", " ", ","); | |
3868 | } | |
3869 | if (e) | |
2e236508 | 3870 | col = write_expression (file, e, col, scol, 0); |
4bae15ec TL |
3871 | col = token_print_indent (file, col, indent, "", "", ")"); |
3872 | break; | |
3873 | ||
2e236508 | 3874 | case expr_ns_add: |
4bae15ec TL |
3875 | col = token_print_indent (file, col, indent, "", "", |
3876 | "update"); | |
3877 | col = token_print_indent (file, col, indent, " ", "", | |
3878 | "("); | |
3879 | scol = col; | |
2e236508 TL |
3880 | sprintf (obuf, "%d", expr -> data.ns_add.rrclass); |
3881 | col = token_print_indent (file, col, scol, "", "", obuf); | |
4bae15ec TL |
3882 | col = token_print_indent (file, col, scol, "", " ", |
3883 | ","); | |
2e236508 TL |
3884 | sprintf (obuf, "%d", expr -> data.ns_add.rrtype); |
3885 | col = token_print_indent (file, col, scol, "", "", obuf); | |
fa098be8 TL |
3886 | col = token_print_indent (file, col, scol, "", " ", |
3887 | ","); | |
2e236508 TL |
3888 | col = write_expression (file, expr -> data.ns_add.rrname, |
3889 | col, scol, 0); | |
fa098be8 TL |
3890 | col = token_print_indent (file, col, scol, "", " ", |
3891 | ","); | |
2e236508 TL |
3892 | col = write_expression (file, expr -> data.ns_add.rrdata, |
3893 | col, scol, 0); | |
fa098be8 TL |
3894 | col = token_print_indent (file, col, scol, "", " ", |
3895 | ","); | |
2e236508 TL |
3896 | col = write_expression (file, expr -> data.ns_add.ttl, |
3897 | col, scol, 0); | |
fa098be8 TL |
3898 | col = token_print_indent (file, col, indent, "", "", |
3899 | ")"); | |
3900 | break; | |
3901 | ||
4bae15ec | 3902 | case expr_ns_delete: |
06a8567c | 3903 | col = token_print_indent (file, col, indent, "", "", |
4bae15ec | 3904 | "delete"); |
846d7d54 TL |
3905 | col = token_print_indent (file, col, indent, " ", "", |
3906 | "("); | |
4bae15ec | 3907 | finish_ns_small: |
846d7d54 | 3908 | scol = col; |
2e236508 TL |
3909 | sprintf (obuf, "%d", expr -> data.ns_add.rrclass); |
3910 | col = token_print_indent (file, col, scol, "", "", obuf); | |
4bae15ec TL |
3911 | col = token_print_indent (file, col, scol, "", " ", |
3912 | ","); | |
2e236508 TL |
3913 | sprintf (obuf, "%d", expr -> data.ns_add.rrtype); |
3914 | col = token_print_indent (file, col, scol, "", "", obuf); | |
4bae15ec TL |
3915 | col = token_print_indent (file, col, scol, "", " ", |
3916 | ","); | |
2e236508 TL |
3917 | col = write_expression (file, expr -> data.ns_add.rrname, |
3918 | col, scol, 0); | |
4bae15ec TL |
3919 | col = token_print_indent (file, col, scol, "", " ", |
3920 | ","); | |
2e236508 TL |
3921 | col = write_expression (file, expr -> data.ns_add.rrdata, |
3922 | col, scol, 0); | |
846d7d54 TL |
3923 | col = token_print_indent (file, col, indent, "", "", |
3924 | ")"); | |
06a8567c TL |
3925 | break; |
3926 | ||
4bae15ec TL |
3927 | case expr_ns_exists: |
3928 | col = token_print_indent (file, col, indent, "", "", | |
3929 | "exists"); | |
3930 | col = token_print_indent (file, col, indent, " ", "", | |
3931 | "("); | |
3932 | goto finish_ns_small; | |
3933 | ||
3934 | case expr_ns_not_exists: | |
2dbc95d6 | 3935 | col = token_print_indent (file, col, indent, "", "", |
4bae15ec TL |
3936 | "not exists"); |
3937 | col = token_print_indent (file, col, indent, " ", "", | |
3938 | "("); | |
3939 | goto finish_ns_small; | |
3940 | ||
2e236508 | 3941 | case expr_static: |
2dbc95d6 | 3942 | col = token_print_indent (file, col, indent, "", "", |
2e236508 | 3943 | "static"); |
2dbc95d6 TL |
3944 | break; |
3945 | ||
2e236508 TL |
3946 | case expr_null: |
3947 | col = token_print_indent (file, col, indent, "", "", "null"); | |
3948 | break; | |
3949 | ||
3950 | case expr_variable_reference: | |
3951 | col = token_print_indent (file, indent, indent, "", "", | |
3952 | expr -> data.variable); | |
3953 | break; | |
3954 | ||
3955 | case expr_variable_exists: | |
3956 | col = token_print_indent (file, indent, indent, "", "", | |
3957 | "defined"); | |
3958 | col = token_print_indent (file, col, indent, " ", "", "("); | |
2dbc95d6 | 3959 | col = token_print_indent (file, col, indent, "", "", |
2e236508 TL |
3960 | expr -> data.variable); |
3961 | col = token_print_indent (file, col, indent, "", "", ")"); | |
2dbc95d6 TL |
3962 | break; |
3963 | ||
fa098be8 TL |
3964 | default: |
3965 | log_fatal ("invalid expression type in print_expression: %d", | |
3966 | expr -> op); | |
3967 | } | |
3968 | return col; | |
3969 | } | |
4cbc378f TL |
3970 | |
3971 | struct binding *find_binding (struct binding_scope *scope, const char *name) | |
3972 | { | |
3973 | struct binding *bp; | |
3974 | struct binding_scope *s; | |
3975 | ||
3976 | for (s = scope; s; s = s -> outer) { | |
3977 | for (bp = s -> bindings; bp; bp = bp -> next) { | |
3978 | if (!strcasecmp (name, bp -> name)) { | |
3979 | return bp; | |
3980 | } | |
3981 | } | |
3982 | } | |
3983 | return (struct binding *)0; | |
3984 | } | |
3985 | ||
4bd8800e | 3986 | int free_bindings (struct binding_scope *scope, const char *file, int line) |
4cbc378f TL |
3987 | { |
3988 | struct binding *bp, *next; | |
3989 | ||
3990 | for (bp = scope -> bindings; bp; bp = next) { | |
3991 | next = bp -> next; | |
3992 | if (bp -> name) | |
4bd8800e | 3993 | dfree (bp -> name, file, line); |
9f7050df TL |
3994 | if (bp -> value) |
3995 | binding_value_dereference (&bp -> value, file, line); | |
4bd8800e | 3996 | dfree (bp, file, line); |
4cbc378f TL |
3997 | } |
3998 | scope -> bindings = (struct binding *)0; | |
3999 | return 1; | |
4000 | } | |
4001 | ||
4bd8800e | 4002 | int binding_scope_dereference (ptr, file, line) |
4cbc378f | 4003 | struct binding_scope **ptr; |
4bd8800e TL |
4004 | const char *file; |
4005 | int line; | |
4cbc378f | 4006 | { |
6ceb9118 TL |
4007 | int i; |
4008 | struct binding_scope *binding_scope; | |
4009 | ||
4cbc378f | 4010 | if (!ptr || !*ptr) { |
4bd8800e | 4011 | log_error ("%s(%d): null pointer", file, line); |
4cbc378f TL |
4012 | #if defined (POINTER_DEBUG) |
4013 | abort (); | |
4014 | #else | |
4015 | return 0; | |
4016 | #endif | |
4017 | } | |
4018 | ||
6ceb9118 | 4019 | binding_scope = *ptr; |
4cbc378f | 4020 | *ptr = (struct binding_scope *)0; |
6ceb9118 | 4021 | --binding_scope -> refcnt; |
d758ad8c | 4022 | rc_register (file, line, ptr, |
98311e4b | 4023 | binding_scope, binding_scope -> refcnt, 1, RC_MISC); |
6ceb9118 TL |
4024 | if (binding_scope -> refcnt > 0) |
4025 | return 1; | |
4026 | ||
4027 | if (binding_scope -> refcnt < 0) { | |
4028 | log_error ("%s(%d): negative refcnt!", file, line); | |
4029 | #if defined (DEBUG_RC_HISTORY) | |
d758ad8c | 4030 | dump_rc_history (binding_scope); |
6ceb9118 TL |
4031 | #endif |
4032 | #if defined (POINTER_DEBUG) | |
4033 | abort (); | |
4034 | #else | |
4035 | return 0; | |
4036 | #endif | |
4037 | } | |
4038 | ||
4039 | free_bindings (binding_scope, file, line); | |
4040 | if (binding_scope -> outer) | |
4041 | binding_scope_dereference (&binding_scope -> outer, MDL); | |
4042 | dfree (binding_scope, file, line); | |
4cbc378f TL |
4043 | return 1; |
4044 | } | |
4045 | ||
800f0de7 TL |
4046 | int fundef_dereference (ptr, file, line) |
4047 | struct fundef **ptr; | |
4048 | const char *file; | |
4049 | int line; | |
4050 | { | |
165bce70 | 4051 | struct fundef *bp = *ptr; |
800f0de7 TL |
4052 | struct string_list *sp, *next; |
4053 | ||
4054 | if (!ptr) { | |
4055 | log_error ("%s(%d): null pointer", file, line); | |
4056 | #if defined (POINTER_DEBUG) | |
4057 | abort (); | |
4058 | #else | |
4059 | return 0; | |
4060 | #endif | |
4061 | } | |
4062 | ||
4063 | if (!bp) { | |
4064 | log_error ("%s(%d): null pointer", file, line); | |
4065 | #if defined (POINTER_DEBUG) | |
4066 | abort (); | |
4067 | #else | |
4068 | return 0; | |
4069 | #endif | |
4070 | } | |
4071 | ||
4072 | bp -> refcnt--; | |
98311e4b | 4073 | rc_register (file, line, ptr, bp, bp -> refcnt, 1, RC_MISC); |
800f0de7 TL |
4074 | if (bp -> refcnt < 0) { |
4075 | log_error ("%s(%d): negative refcnt!", file, line); | |
4076 | #if defined (DEBUG_RC_HISTORY) | |
d758ad8c | 4077 | dump_rc_history (bp); |
800f0de7 TL |
4078 | #endif |
4079 | #if defined (POINTER_DEBUG) | |
4080 | abort (); | |
4081 | #else | |
4082 | return 0; | |
4083 | #endif | |
4084 | } | |
4085 | if (!bp -> refcnt) { | |
4086 | for (sp = bp -> args; sp; sp = next) { | |
4087 | next = sp -> next; | |
4088 | dfree (sp, file, line); | |
4089 | } | |
4090 | if (bp -> statements) | |
4091 | executable_statement_dereference (&bp -> statements, | |
4092 | file, line); | |
4093 | dfree (bp, file, line); | |
4094 | } | |
4095 | *ptr = (struct fundef *)0; | |
4096 | return 1; | |
4097 | } | |
4098 | ||
975bd464 TL |
4099 | #if defined (NOTYET) /* Post 3.0 final. */ |
4100 | int data_subexpression_length (int *rv, | |
4101 | struct expression *expr) | |
4102 | { | |
4103 | int crhs, clhs, llhs, lrhs; | |
4104 | switch (expr -> op) { | |
4105 | case expr_substring: | |
4106 | if (expr -> data.substring.len && | |
4107 | expr -> data.substring.len -> op == expr_const_int) { | |
4108 | (*rv = | |
4109 | (int)expr -> data.substring.len -> data.const_int); | |
4110 | return 1; | |
4111 | } | |
4112 | return 0; | |
4113 | ||
4114 | case expr_packet: | |
4115 | case expr_suffix: | |
4116 | if (expr -> data.suffix.len && | |
4117 | expr -> data.suffix.len -> op == expr_const_int) { | |
4118 | (*rv = | |
4119 | (int)expr -> data.suffix.len -> data.const_int); | |
4120 | return 1; | |
4121 | } | |
4122 | return 0; | |
4123 | ||
2727c1cf DH |
4124 | case expr_lcase: |
4125 | return data_subexpression_length(rv, expr->data.lcase); | |
4126 | ||
4127 | case expr_ucase: | |
4128 | return data_subexpression_length(rv, expr->data.ucase); | |
4129 | ||
975bd464 TL |
4130 | case expr_concat: |
4131 | clhs = data_subexpression_length (&llhs, | |
4132 | expr -> data.concat [0]); | |
4133 | crhs = data_subexpression_length (&lrhs, | |
4134 | expr -> data.concat [1]); | |
4135 | if (crhs == 0 || clhs == 0) | |
4136 | return 0; | |
4137 | *rv = llhs + lrhs; | |
4138 | return 1; | |
4139 | break; | |
4140 | ||
4141 | case expr_hardware: | |
4142 | return 0; | |
4143 | ||
4144 | case expr_const_data: | |
4145 | *rv = expr -> data.const_data.len; | |
4146 | return 2; | |
4147 | ||
4148 | case expr_reverse: | |
4149 | return data_subexpression_length (rv, | |
4150 | expr -> data.reverse.buffer); | |
4151 | ||
4152 | case expr_leased_address: | |
4153 | case expr_lease_time: | |
4154 | *rv = 4; | |
4155 | return 2; | |
4156 | ||
4157 | case expr_pick_first_value: | |
4158 | clhs = data_subexpression_length (&llhs, | |
4159 | expr -> data.concat [0]); | |
4160 | crhs = data_subexpression_length (&lrhs, | |
4161 | expr -> data.concat [1]); | |
4162 | if (crhs == 0 || clhs == 0) | |
4163 | return 0; | |
4164 | if (llhs > lrhs) | |
4165 | *rv = llhs; | |
4166 | else | |
4167 | *rv = lrhs; | |
4168 | return 1; | |
4169 | ||
4170 | case expr_binary_to_ascii: | |
4171 | case expr_config_option: | |
4172 | case expr_host_decl_name: | |
4173 | case expr_encapsulate: | |
4174 | case expr_filename: | |
4175 | case expr_sname: | |
4176 | case expr_host_lookup: | |
4177 | case expr_option: | |
4178 | case expr_none: | |
4179 | case expr_match: | |
4180 | case expr_check: | |
4181 | case expr_equal: | |
4182 | case expr_and: | |
4183 | case expr_or: | |
4184 | case expr_not: | |
4185 | case expr_extract_int8: | |
4186 | case expr_extract_int16: | |
4187 | case expr_extract_int32: | |
4188 | case expr_encode_int8: | |
4189 | case expr_encode_int16: | |
4190 | case expr_encode_int32: | |
4191 | case expr_const_int: | |
4192 | case expr_exists: | |
4193 | case expr_known: | |
4194 | case expr_dns_transaction: | |
4195 | case expr_static: | |
4196 | case expr_ns_add: | |
4197 | case expr_ns_delete: | |
4198 | case expr_ns_exists: | |
4199 | case expr_ns_not_exists: | |
4200 | case expr_not_equal: | |
4201 | case expr_null: | |
4202 | case expr_variable_exists: | |
4203 | case expr_variable_reference: | |
4204 | case expr_arg: | |
4205 | case expr_funcall: | |
4206 | case expr_function: | |
4207 | case expr_add: | |
4208 | case expr_subtract: | |
4209 | case expr_multiply: | |
4210 | case expr_divide: | |
4211 | case expr_remainder: | |
4212 | case expr_binary_and: | |
4213 | case expr_binary_or: | |
4214 | case expr_binary_xor: | |
16121af5 | 4215 | case expr_client_state: |
975bd464 TL |
4216 | return 0; |
4217 | } | |
4218 | return 0; | |
4219 | } | |
4220 | ||
4221 | int expr_valid_for_context (struct expression *expr, | |
4222 | enum expression_context context) | |
4223 | { | |
4224 | /* We don't know at parse time what type of value a function may | |
4225 | return, so we can't flag an error on it. */ | |
4226 | if (expr -> op == expr_funcall || | |
4227 | expr -> op == expr_variable_reference) | |
4228 | return 1; | |
4229 | ||
4230 | switch (context) { | |
4231 | case context_any: | |
4232 | return 1; | |
4233 | ||
4234 | case context_boolean: | |
4235 | if (is_boolean_expression (expr)) | |
4236 | return 1; | |
4237 | return 0; | |
4238 | ||
4239 | case context_data: | |
4240 | if (is_data_expression (expr)) | |
4241 | return 1; | |
4242 | return 0; | |
4243 | ||
4244 | case context_numeric: | |
4245 | if (is_numeric_expression (expr)) | |
4246 | return 1; | |
4247 | return 0; | |
4248 | ||
4249 | case context_dns: | |
4250 | if (is_dns_expression (expr)) { | |
4251 | return 1; | |
4252 | } | |
4253 | return 0; | |
4254 | ||
4255 | case context_data_or_numeric: | |
4256 | if (is_numeric_expression (expr) || | |
4257 | is_data_expression (expr)) { | |
4258 | return 1; | |
4259 | } | |
4260 | return 0; | |
4261 | ||
4262 | case context_function: | |
4263 | if (expr -> op == expr_function) | |
4264 | return 1; | |
4265 | return 0; | |
4266 | } | |
4267 | return 0; | |
4268 | } | |
4269 | #endif /* NOTYET */ | |
4270 | ||
79c36eb7 TL |
4271 | struct binding *create_binding (struct binding_scope **scope, const char *name) |
4272 | { | |
4273 | struct binding *binding; | |
4274 | ||
4275 | if (!*scope) { | |
4276 | if (!binding_scope_allocate (scope, MDL)) | |
4277 | return (struct binding *)0; | |
4278 | } | |
4279 | ||
4280 | binding = find_binding (*scope, name); | |
4281 | if (!binding) { | |
4282 | binding = dmalloc (sizeof *binding, MDL); | |
4283 | if (!binding) | |
4284 | return (struct binding *)0; | |
4285 | ||
4286 | memset (binding, 0, sizeof *binding); | |
4287 | binding -> name = dmalloc (strlen (name) + 1, MDL); | |
4288 | if (!binding -> name) { | |
4289 | dfree (binding, MDL); | |
4290 | return (struct binding *)0; | |
4291 | } | |
4292 | strcpy (binding -> name, name); | |
4293 | ||
4294 | binding -> next = (*scope) -> bindings; | |
4295 | (*scope) -> bindings = binding; | |
4296 | } | |
4297 | ||
4298 | return binding; | |
4299 | } | |
4300 | ||
4301 | ||
4302 | int bind_ds_value (struct binding_scope **scope, | |
4303 | const char *name, | |
4304 | struct data_string *value) | |
4305 | { | |
4306 | struct binding *binding; | |
4307 | ||
4308 | binding = create_binding (scope, name); | |
4309 | if (!binding) | |
4310 | return 0; | |
4311 | ||
4312 | if (binding -> value) | |
4313 | binding_value_dereference (&binding -> value, MDL); | |
4314 | ||
4315 | if (!binding_value_allocate (&binding -> value, MDL)) | |
4316 | return 0; | |
4317 | ||
4318 | data_string_copy (&binding -> value -> value.data, value, MDL); | |
4319 | binding -> value -> type = binding_data; | |
4320 | ||
4321 | return 1; | |
4322 | } | |
4323 | ||
4324 | ||
4325 | int find_bound_string (struct data_string *value, | |
4326 | struct binding_scope *scope, | |
4327 | const char *name) | |
4328 | { | |
4329 | struct binding *binding; | |
4330 | ||
4331 | binding = find_binding (scope, name); | |
4332 | if (!binding || | |
4333 | !binding -> value || | |
4334 | binding -> value -> type != binding_data) | |
4335 | return 0; | |
4336 | ||
4337 | if (binding -> value -> value.data.terminated) { | |
4338 | data_string_copy (value, &binding -> value -> value.data, MDL); | |
4339 | } else { | |
4340 | buffer_allocate (&value -> buffer, | |
4341 | binding -> value -> value.data.len, | |
4342 | MDL); | |
4343 | if (!value -> buffer) | |
4344 | return 0; | |
4345 | ||
4346 | memcpy (value -> buffer -> data, | |
4347 | binding -> value -> value.data.data, | |
4348 | binding -> value -> value.data.len); | |
4349 | value -> data = value -> buffer -> data; | |
4350 | value -> len = binding -> value -> value.data.len; | |
4351 | } | |
4352 | ||
4353 | return 1; | |
4354 | } | |
4355 | ||
4356 | int unset (struct binding_scope *scope, const char *name) | |
4357 | { | |
4358 | struct binding *binding; | |
4359 | ||
4360 | binding = find_binding (scope, name); | |
4361 | if (binding) { | |
4362 | if (binding -> value) | |
4363 | binding_value_dereference | |
4364 | (&binding -> value, MDL); | |
4365 | return 1; | |
4366 | } | |
4367 | return 0; | |
4368 | } | |
4369 | ||
b860910b | 4370 | /* vim: set tabstop=8: */ |