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