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