1: /* tree.c
2:
3: Routines for manipulating parse trees... */
4:
5: /*
6: * Copyright (c) 2011-2012 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: int rc = 0;
2383:
2384: switch (expr -> op) {
2385: case expr_check:
2386: case expr_equal:
2387: case expr_not_equal:
2388: case expr_regex_match:
2389: case expr_iregex_match:
2390: case expr_and:
2391: case expr_or:
2392: case expr_not:
2393: case expr_match:
2394: case expr_static:
2395: case expr_known:
2396: case expr_none:
2397: case expr_exists:
2398: case expr_variable_exists:
2399: log_error ("Boolean opcode in evaluate_numeric_expression: %d",
2400: expr -> op);
2401: return 0;
2402:
2403: case expr_substring:
2404: case expr_suffix:
2405: case expr_lcase:
2406: case expr_ucase:
2407: case expr_option:
2408: case expr_hardware:
2409: case expr_const_data:
2410: case expr_packet:
2411: case expr_concat:
2412: case expr_encapsulate:
2413: case expr_host_lookup:
2414: case expr_encode_int8:
2415: case expr_encode_int16:
2416: case expr_encode_int32:
2417: case expr_binary_to_ascii:
2418: case expr_reverse:
2419: case expr_filename:
2420: case expr_sname:
2421: case expr_pick_first_value:
2422: case expr_host_decl_name:
2423: case expr_config_option:
2424: case expr_leased_address:
2425: case expr_null:
2426: log_error ("Data opcode in evaluate_numeric_expression: %d",
2427: expr -> op);
2428: return 0;
2429:
2430: case expr_extract_int8:
2431: memset (&data, 0, sizeof data);
2432: status = evaluate_data_expression
2433: (&data, packet, lease, client_state, in_options,
2434: cfg_options, scope, expr -> data.extract_int, MDL);
2435: if (status)
2436: *result = data.data [0];
2437: #if defined (DEBUG_EXPRESSIONS)
2438: log_debug ("num: extract_int8 (%s) = %s",
2439: status ? print_hex_1 (data.len, data.data, 60) : "NULL",
2440: status ? print_dec_1 (*result) : "NULL" );
2441: #endif
2442: if (status) data_string_forget (&data, MDL);
2443: return status;
2444:
2445: case expr_extract_int16:
2446: memset (&data, 0, sizeof data);
2447: status = (evaluate_data_expression
2448: (&data, packet, lease, client_state, in_options,
2449: cfg_options, scope, expr -> data.extract_int, MDL));
2450: if (status && data.len >= 2) {
2451: *result = getUShort (data.data);
2452: rc = 1;
2453: }
2454: #if defined (DEBUG_EXPRESSIONS)
2455: if (rc == 1) {
2456: log_debug ("num: extract_int16 (%s) = %ld",
2457: print_hex_1(data.len, data.data, 60)
2458: *result);
2459: } else {
2460: log_debug ("num: extract_int16 (NULL) = NULL");
2461: }
2462: #endif
2463: if (status) data_string_forget (&data, MDL);
2464: return (rc);
2465:
2466: case expr_extract_int32:
2467: memset (&data, 0, sizeof data);
2468: status = (evaluate_data_expression
2469: (&data, packet, lease, client_state, in_options,
2470: cfg_options, scope, expr -> data.extract_int, MDL));
2471: if (status && data.len >= 4) {
2472: *result = getULong (data.data);
2473: rc = 1;
2474: }
2475: #if defined (DEBUG_EXPRESSIONS)
2476: if (rc == 1) {
2477: log_debug ("num: extract_int32 (%s) = %ld",
2478: print_hex_1 (data.len, data.data, 60),
2479: *result);
2480: } else {
2481: log_debug ("num: extract_int32 (NULL) = NULL");
2482: }
2483: #endif
2484: if (status) data_string_forget (&data, MDL);
2485: return (rc);
2486:
2487: case expr_const_int:
2488: *result = expr -> data.const_int;
2489: #if defined (DEBUG_EXPRESSIONS)
2490: log_debug ("number: CONSTANT = %ld", *result);
2491: #endif
2492: return 1;
2493:
2494: case expr_lease_time:
2495: if (!lease) {
2496: log_error ("data: leased_lease: not available");
2497: return 0;
2498: }
2499: if (lease -> ends < cur_time) {
2500: log_error ("%s %lu when it is now %lu",
2501: "data: lease_time: lease ends at",
2502: (long)(lease -> ends), (long)cur_time);
2503: return 0;
2504: }
2505: *result = lease -> ends - cur_time;
2506: #if defined (DEBUG_EXPRESSIONS)
2507: log_debug ("number: lease-time = (%lu - %lu) = %ld",
2508: lease -> ends,
2509: cur_time, *result);
2510: #endif
2511: return 1;
2512:
2513: case expr_dns_transaction:
2514: #if !defined (NSUPDATE)
2515: return 0;
2516: #else
2517: if (!resolver_inited) {
2518: minires_ninit (&resolver_state);
2519: resolver_inited = 1;
2520: resolver_state.retrans = 1;
2521: resolver_state.retry = 1;
2522: }
2523: ISC_LIST_INIT (uq);
2524: cur = expr;
2525: do {
2526: next = cur -> data.dns_transaction.cdr;
2527: nut = 0;
2528: status = (evaluate_dns_expression
2529: (&nut, packet,
2530: lease, client_state, in_options, cfg_options,
2531: scope, cur -> data.dns_transaction.car));
2532: if (!status)
2533: goto dns_bad;
2534: ISC_LIST_APPEND (uq, nut, r_link);
2535: cur = next;
2536: } while (next);
2537:
2538: /* Do the update and record the error code, if there was
2539: an error; otherwise set it to NOERROR. */
2540: *result = minires_nupdate (&resolver_state,
2541: ISC_LIST_HEAD (uq));
2542: status = 1;
2543:
2544: print_dns_status ((int)*result, &uq);
2545:
2546: dns_bad:
2547: while (!ISC_LIST_EMPTY (uq)) {
2548: ns_updrec *tmp = ISC_LIST_HEAD (uq);
2549: ISC_LIST_UNLINK (uq, tmp, r_link);
2550: if (tmp -> r_data_ephem) {
2551: dfree (tmp -> r_data_ephem, MDL);
2552: tmp -> r_data = (unsigned char *)0;
2553: tmp -> r_data_ephem = (unsigned char *)0;
2554: }
2555: minires_freeupdrec (tmp);
2556: }
2557: return status;
2558: #endif /* NSUPDATE */
2559:
2560: case expr_variable_reference:
2561: if (scope && *scope) {
2562: binding = find_binding (*scope, expr -> data.variable);
2563:
2564: if (binding && binding -> value) {
2565: if (binding -> value -> type == binding_numeric) {
2566: *result = binding -> value -> value.intval;
2567: status = 1;
2568: } else {
2569: log_error ("binding type %d in %s.",
2570: binding -> value -> type,
2571: "evaluate_numeric_expression");
2572: status = 0;
2573: }
2574: } else
2575: status = 0;
2576: } else
2577: status = 0;
2578: #if defined (DEBUG_EXPRESSIONS)
2579: if (status)
2580: log_debug ("numeric: %s = %ld",
2581: expr -> data.variable, *result);
2582: else
2583: log_debug ("numeric: %s = NULL",
2584: expr -> data.variable);
2585: #endif
2586: return status;
2587:
2588: case expr_funcall:
2589: bv = (struct binding_value *)0;
2590: status = evaluate_expression (&bv, packet, lease,
2591: client_state,
2592: in_options, cfg_options,
2593: scope, expr, MDL);
2594: if (status) {
2595: if (bv -> type != binding_numeric)
2596: log_error ("%s() returned type %d in %s.",
2597: expr -> data.funcall.name,
2598: bv -> type,
2599: "evaluate_numeric_expression");
2600: else
2601: *result = bv -> value.intval;
2602: binding_value_dereference (&bv, MDL);
2603: }
2604: #if defined (DEBUG_EXPRESSIONS)
2605: log_debug ("data: %s = %ld", expr -> data.funcall.name,
2606: status ? *result : 0);
2607: #endif
2608: break;
2609:
2610: case expr_add:
2611: sleft = evaluate_numeric_expression (&ileft, packet, lease,
2612: client_state,
2613: in_options, cfg_options,
2614: scope,
2615: expr -> data.and [0]);
2616: sright = evaluate_numeric_expression (&iright, packet, lease,
2617: client_state,
2618: in_options, cfg_options,
2619: scope,
2620: expr -> data.and [1]);
2621:
2622: #if defined (DEBUG_EXPRESSIONS)
2623: if (sleft && sright)
2624: log_debug ("num: %ld + %ld = %ld",
2625: ileft, iright, ileft + iright);
2626: else if (sleft)
2627: log_debug ("num: %ld + NULL = NULL", ileft);
2628: else
2629: log_debug ("num: NULL + %ld = NULL", iright);
2630: #endif
2631: if (sleft && sright) {
2632: *result = ileft + iright;
2633: return 1;
2634: }
2635: return 0;
2636:
2637: case expr_subtract:
2638: sleft = evaluate_numeric_expression (&ileft, packet, lease,
2639: client_state,
2640: in_options, cfg_options,
2641: scope,
2642: expr -> data.and [0]);
2643: sright = evaluate_numeric_expression (&iright, packet, lease,
2644: client_state,
2645: in_options, cfg_options,
2646: scope,
2647: expr -> data.and [1]);
2648:
2649: #if defined (DEBUG_EXPRESSIONS)
2650: if (sleft && sright)
2651: log_debug ("num: %ld - %ld = %ld",
2652: ileft, iright, ileft - iright);
2653: else if (sleft)
2654: log_debug ("num: %ld - NULL = NULL", ileft);
2655: else
2656: log_debug ("num: NULL - %ld = NULL", iright);
2657: #endif
2658: if (sleft && sright) {
2659: *result = ileft - iright;
2660: return 1;
2661: }
2662: return 0;
2663:
2664: case expr_multiply:
2665: sleft = evaluate_numeric_expression (&ileft, packet, lease,
2666: client_state,
2667: in_options, cfg_options,
2668: scope,
2669: expr -> data.and [0]);
2670: sright = evaluate_numeric_expression (&iright, packet, lease,
2671: client_state,
2672: in_options, cfg_options,
2673: scope,
2674: expr -> data.and [1]);
2675:
2676: #if defined (DEBUG_EXPRESSIONS)
2677: if (sleft && sright)
2678: log_debug ("num: %ld * %ld = %ld",
2679: ileft, iright, ileft * iright);
2680: else if (sleft)
2681: log_debug ("num: %ld * NULL = NULL", ileft);
2682: else
2683: log_debug ("num: NULL * %ld = NULL", iright);
2684: #endif
2685: if (sleft && sright) {
2686: *result = ileft * iright;
2687: return 1;
2688: }
2689: return 0;
2690:
2691: case expr_divide:
2692: sleft = evaluate_numeric_expression (&ileft, packet, lease,
2693: client_state,
2694: in_options, cfg_options,
2695: scope,
2696: expr -> data.and [0]);
2697: sright = evaluate_numeric_expression (&iright, packet, lease,
2698: client_state,
2699: in_options, cfg_options,
2700: scope,
2701: expr -> data.and [1]);
2702:
2703: #if defined (DEBUG_EXPRESSIONS)
2704: if (sleft && sright) {
2705: if (iright != 0)
2706: log_debug ("num: %ld / %ld = %ld",
2707: ileft, iright, ileft / iright);
2708: else
2709: log_debug ("num: %ld / %ld = NULL",
2710: ileft, iright);
2711: } else if (sleft)
2712: log_debug ("num: %ld / NULL = NULL", ileft);
2713: else
2714: log_debug ("num: NULL / %ld = NULL", iright);
2715: #endif
2716: if (sleft && sright && iright) {
2717: *result = ileft / iright;
2718: return 1;
2719: }
2720: return 0;
2721:
2722: case expr_remainder:
2723: sleft = evaluate_numeric_expression (&ileft, packet, lease,
2724: client_state,
2725: in_options, cfg_options,
2726: scope,
2727: expr -> data.and [0]);
2728: sright = evaluate_numeric_expression (&iright, packet, lease,
2729: client_state,
2730: in_options, cfg_options,
2731: scope,
2732: expr -> data.and [1]);
2733:
2734: #if defined (DEBUG_EXPRESSIONS)
2735: if (sleft && sright) {
2736: if (iright != 0)
2737: log_debug ("num: %ld %% %ld = %ld",
2738: ileft, iright, ileft % iright);
2739: else
2740: log_debug ("num: %ld %% %ld = NULL",
2741: ileft, iright);
2742: } else if (sleft)
2743: log_debug ("num: %ld %% NULL = NULL", ileft);
2744: else
2745: log_debug ("num: NULL %% %ld = NULL", iright);
2746: #endif
2747: if (sleft && sright && iright) {
2748: *result = ileft % iright;
2749: return 1;
2750: }
2751: return 0;
2752:
2753: case expr_binary_and:
2754: sleft = evaluate_numeric_expression (&ileft, packet, lease,
2755: client_state,
2756: in_options, cfg_options,
2757: scope,
2758: expr -> data.and [0]);
2759: sright = evaluate_numeric_expression (&iright, packet, lease,
2760: client_state,
2761: in_options, cfg_options,
2762: scope,
2763: expr -> data.and [1]);
2764:
2765: #if defined (DEBUG_EXPRESSIONS)
2766: if (sleft && sright)
2767: log_debug ("num: %ld | %ld = %ld",
2768: ileft, iright, ileft & iright);
2769: else if (sleft)
2770: log_debug ("num: %ld & NULL = NULL", ileft);
2771: else
2772: log_debug ("num: NULL & %ld = NULL", iright);
2773: #endif
2774: if (sleft && sright) {
2775: *result = ileft & iright;
2776: return 1;
2777: }
2778: return 0;
2779:
2780: case expr_binary_or:
2781: sleft = evaluate_numeric_expression (&ileft, packet, lease,
2782: client_state,
2783: in_options, cfg_options,
2784: scope,
2785: expr -> data.and [0]);
2786: sright = evaluate_numeric_expression (&iright, packet, lease,
2787: client_state,
2788: in_options, cfg_options,
2789: scope,
2790: expr -> data.and [1]);
2791:
2792: #if defined (DEBUG_EXPRESSIONS)
2793: if (sleft && sright)
2794: log_debug ("num: %ld | %ld = %ld",
2795: ileft, iright, ileft | iright);
2796: else if (sleft)
2797: log_debug ("num: %ld | NULL = NULL", ileft);
2798: else
2799: log_debug ("num: NULL | %ld = NULL", iright);
2800: #endif
2801: if (sleft && sright) {
2802: *result = ileft | iright;
2803: return 1;
2804: }
2805: return 0;
2806:
2807: case expr_binary_xor:
2808: sleft = evaluate_numeric_expression (&ileft, packet, lease,
2809: client_state,
2810: in_options, cfg_options,
2811: scope,
2812: expr -> data.and [0]);
2813: sright = evaluate_numeric_expression (&iright, packet, lease,
2814: client_state,
2815: in_options, cfg_options,
2816: scope,
2817: expr -> data.and [1]);
2818:
2819: #if defined (DEBUG_EXPRESSIONS)
2820: if (sleft && sright)
2821: log_debug ("num: %ld ^ %ld = %ld",
2822: ileft, iright, ileft ^ iright);
2823: else if (sleft)
2824: log_debug ("num: %ld ^ NULL = NULL", ileft);
2825: else
2826: log_debug ("num: NULL ^ %ld = NULL", iright);
2827: #endif
2828: if (sleft && sright) {
2829: *result = ileft ^ iright;
2830: return 1;
2831: }
2832: return 0;
2833:
2834: case expr_client_state:
2835: if (client_state) {
2836: #if defined (DEBUG_EXPRESSIONS)
2837: log_debug ("num: client-state = %d",
2838: client_state -> state);
2839: #endif
2840: *result = client_state -> state;
2841: return 1;
2842: } else {
2843: #if defined (DEBUG_EXPRESSIONS)
2844: log_debug ("num: client-state = NULL");
2845: #endif
2846: return 0;
2847: }
2848:
2849: case expr_ns_add:
2850: case expr_ns_delete:
2851: case expr_ns_exists:
2852: case expr_ns_not_exists:
2853: log_error ("dns opcode in evaluate_numeric_expression: %d",
2854: expr -> op);
2855: return 0;
2856:
2857: case expr_function:
2858: log_error ("function definition in evaluate_numeric_expr");
2859: return 0;
2860:
2861: case expr_arg:
2862: break;
2863:
2864: default:
2865: log_fatal("Impossible case at %s:%d. Undefined operator "
2866: "%d.", MDL, expr->op);
2867: break;
2868: }
2869:
2870: log_error ("evaluate_numeric_expression: bogus opcode %d", expr -> op);
2871: return 0;
2872: }
2873:
2874: /* Return data hanging off of an option cache structure, or if there
2875: isn't any, evaluate the expression hanging off of it and return the
2876: result of that evaluation. There should never be both an expression
2877: and a valid data_string. */
2878:
2879: int evaluate_option_cache (result, packet, lease, client_state,
2880: in_options, cfg_options, scope, oc, file, line)
2881: struct data_string *result;
2882: struct packet *packet;
2883: struct lease *lease;
2884: struct client_state *client_state;
2885: struct option_state *in_options;
2886: struct option_state *cfg_options;
2887: struct binding_scope **scope;
2888: struct option_cache *oc;
2889: const char *file;
2890: int line;
2891: {
2892: if (oc->data.data != NULL) {
2893: data_string_copy (result, &oc -> data, file, line);
2894: return 1;
2895: }
2896: if (!oc -> expression)
2897: return 0;
2898: return evaluate_data_expression (result, packet, lease, client_state,
2899: in_options, cfg_options, scope,
2900: oc -> expression, file, line);
2901: }
2902:
2903: /* Evaluate an option cache and extract a boolean from the result,
2904: returning the boolean. Return false if there is no data. */
2905:
2906: int evaluate_boolean_option_cache (ignorep, packet,
2907: lease, client_state, in_options,
2908: cfg_options, scope, oc, file, line)
2909: int *ignorep;
2910: struct packet *packet;
2911: struct lease *lease;
2912: struct client_state *client_state;
2913: struct option_state *in_options;
2914: struct option_state *cfg_options;
2915: struct binding_scope **scope;
2916: struct option_cache *oc;
2917: const char *file;
2918: int line;
2919: {
2920: struct data_string ds;
2921: int result;
2922:
2923: /* So that we can be called with option_lookup as an argument. */
2924: if (!oc || !in_options)
2925: return 0;
2926:
2927: memset (&ds, 0, sizeof ds);
2928: if (!evaluate_option_cache (&ds, packet,
2929: lease, client_state, in_options,
2930: cfg_options, scope, oc, file, line))
2931: return 0;
2932:
2933: /* The boolean option cache is actually a trinary value. Zero is
2934: * off, one is on, and 2 is 'ignore'.
2935: */
2936: if (ds.len) {
2937: result = ds.data [0];
2938: if (result == 2) {
2939: result = 0;
2940: if (ignorep != NULL)
2941: *ignorep = 1;
2942: } else if (ignorep != NULL)
2943: *ignorep = 0;
2944: } else
2945: result = 0;
2946: data_string_forget (&ds, MDL);
2947: return result;
2948: }
2949:
2950:
2951: /* Evaluate a boolean expression and return the result of the evaluation,
2952: or FALSE if it failed. */
2953:
2954: int evaluate_boolean_expression_result (ignorep, packet, lease, client_state,
2955: in_options, cfg_options, scope, expr)
2956: int *ignorep;
2957: struct packet *packet;
2958: struct lease *lease;
2959: struct client_state *client_state;
2960: struct option_state *in_options;
2961: struct option_state *cfg_options;
2962: struct binding_scope **scope;
2963: struct expression *expr;
2964: {
2965: int result;
2966:
2967: /* So that we can be called with option_lookup as an argument. */
2968: if (!expr)
2969: return 0;
2970:
2971: if (!evaluate_boolean_expression (&result, packet, lease, client_state,
2972: in_options, cfg_options,
2973: scope, expr))
2974: return 0;
2975:
2976: if (result == 2) {
2977: *ignorep = 1;
2978: result = 0;
2979: } else
2980: *ignorep = 0;
2981: return result;
2982: }
2983:
2984:
2985: /* Dereference an expression node, and if the reference count goes to zero,
2986: dereference any data it refers to, and then free it. */
2987: void expression_dereference (eptr, file, line)
2988: struct expression **eptr;
2989: const char *file;
2990: int line;
2991: {
2992: struct expression *expr = *eptr;
2993:
2994: /* Zero the pointer. */
2995: *eptr = (struct expression *)0;
2996:
2997: /* Decrement the reference count. If it's nonzero, we're
2998: done. */
2999: --(expr -> refcnt);
3000: rc_register (file, line, eptr, expr, expr -> refcnt, 1, RC_MISC);
3001: if (expr -> refcnt > 0)
3002: return;
3003: if (expr -> refcnt < 0) {
3004: log_error ("%s(%d): negative refcnt!", file, line);
3005: #if defined (DEBUG_RC_HISTORY)
3006: dump_rc_history (expr);
3007: #endif
3008: #if defined (POINTER_DEBUG)
3009: abort ();
3010: #else
3011: return;
3012: #endif
3013: }
3014:
3015: /* Dereference subexpressions. */
3016: switch (expr -> op) {
3017: /* All the binary operators can be handled the same way. */
3018: case expr_equal:
3019: case expr_not_equal:
3020: case expr_regex_match:
3021: case expr_iregex_match:
3022: case expr_concat:
3023: case expr_and:
3024: case expr_or:
3025: case expr_add:
3026: case expr_subtract:
3027: case expr_multiply:
3028: case expr_divide:
3029: case expr_remainder:
3030: case expr_binary_and:
3031: case expr_binary_or:
3032: case expr_binary_xor:
3033: case expr_client_state:
3034: if (expr -> data.equal [0])
3035: expression_dereference (&expr -> data.equal [0],
3036: file, line);
3037: if (expr -> data.equal [1])
3038: expression_dereference (&expr -> data.equal [1],
3039: file, line);
3040: break;
3041:
3042: case expr_substring:
3043: if (expr -> data.substring.expr)
3044: expression_dereference (&expr -> data.substring.expr,
3045: file, line);
3046: if (expr -> data.substring.offset)
3047: expression_dereference (&expr -> data.substring.offset,
3048: file, line);
3049: if (expr -> data.substring.len)
3050: expression_dereference (&expr -> data.substring.len,
3051: file, line);
3052: break;
3053:
3054: case expr_suffix:
3055: if (expr -> data.suffix.expr)
3056: expression_dereference (&expr -> data.suffix.expr,
3057: file, line);
3058: if (expr -> data.suffix.len)
3059: expression_dereference (&expr -> data.suffix.len,
3060: file, line);
3061: break;
3062:
3063: case expr_lcase:
3064: if (expr->data.lcase)
3065: expression_dereference(&expr->data.lcase, MDL);
3066: break;
3067:
3068: case expr_ucase:
3069: if (expr->data.ucase)
3070: expression_dereference(&expr->data.ucase, MDL);
3071: break;
3072:
3073: case expr_not:
3074: if (expr -> data.not)
3075: expression_dereference (&expr -> data.not, file, line);
3076: break;
3077:
3078: case expr_packet:
3079: if (expr -> data.packet.offset)
3080: expression_dereference (&expr -> data.packet.offset,
3081: file, line);
3082: if (expr -> data.packet.len)
3083: expression_dereference (&expr -> data.packet.len,
3084: file, line);
3085: break;
3086:
3087: case expr_extract_int8:
3088: case expr_extract_int16:
3089: case expr_extract_int32:
3090: if (expr -> data.extract_int)
3091: expression_dereference (&expr -> data.extract_int,
3092: file, line);
3093: break;
3094:
3095: case expr_encode_int8:
3096: case expr_encode_int16:
3097: case expr_encode_int32:
3098: if (expr -> data.encode_int)
3099: expression_dereference (&expr -> data.encode_int,
3100: file, line);
3101: break;
3102:
3103: case expr_encapsulate:
3104: case expr_const_data:
3105: data_string_forget (&expr -> data.const_data, file, line);
3106: break;
3107:
3108: case expr_host_lookup:
3109: if (expr -> data.host_lookup)
3110: dns_host_entry_dereference (&expr -> data.host_lookup,
3111: file, line);
3112: break;
3113:
3114: case expr_binary_to_ascii:
3115: if (expr -> data.b2a.base)
3116: expression_dereference (&expr -> data.b2a.base,
3117: file, line);
3118: if (expr -> data.b2a.width)
3119: expression_dereference (&expr -> data.b2a.width,
3120: file, line);
3121: if (expr -> data.b2a.separator)
3122: expression_dereference (&expr -> data.b2a.separator,
3123: file, line);
3124: if (expr -> data.b2a.buffer)
3125: expression_dereference (&expr -> data.b2a.buffer,
3126: file, line);
3127: break;
3128:
3129: case expr_pick_first_value:
3130: if (expr -> data.pick_first_value.car)
3131: expression_dereference (&expr -> data.pick_first_value.car,
3132: file, line);
3133: if (expr -> data.pick_first_value.cdr)
3134: expression_dereference (&expr -> data.pick_first_value.cdr,
3135: file, line);
3136: break;
3137:
3138: case expr_reverse:
3139: if (expr -> data.reverse.width)
3140: expression_dereference (&expr -> data.reverse.width,
3141: file, line);
3142: if (expr -> data.reverse.buffer)
3143: expression_dereference
3144: (&expr -> data.reverse.buffer, file, line);
3145: break;
3146:
3147: case expr_dns_transaction:
3148: if (expr -> data.dns_transaction.car)
3149: expression_dereference (&expr -> data.dns_transaction.car,
3150: file, line);
3151: if (expr -> data.dns_transaction.cdr)
3152: expression_dereference (&expr -> data.dns_transaction.cdr,
3153: file, line);
3154: break;
3155:
3156: case expr_ns_add:
3157: if (expr -> data.ns_add.rrname)
3158: expression_dereference (&expr -> data.ns_add.rrname,
3159: file, line);
3160: if (expr -> data.ns_add.rrdata)
3161: expression_dereference (&expr -> data.ns_add.rrdata,
3162: file, line);
3163: if (expr -> data.ns_add.ttl)
3164: expression_dereference (&expr -> data.ns_add.ttl,
3165: file, line);
3166: break;
3167:
3168: case expr_ns_delete:
3169: case expr_ns_exists:
3170: case expr_ns_not_exists:
3171: if (expr -> data.ns_delete.rrname)
3172: expression_dereference (&expr -> data.ns_delete.rrname,
3173: file, line);
3174: if (expr -> data.ns_delete.rrdata)
3175: expression_dereference (&expr -> data.ns_delete.rrdata,
3176: file, line);
3177: break;
3178:
3179: case expr_variable_reference:
3180: case expr_variable_exists:
3181: if (expr -> data.variable)
3182: dfree (expr -> data.variable, file, line);
3183: break;
3184:
3185: case expr_funcall:
3186: if (expr -> data.funcall.name)
3187: dfree (expr -> data.funcall.name, file, line);
3188: if (expr -> data.funcall.arglist)
3189: expression_dereference (&expr -> data.funcall.arglist,
3190: file, line);
3191: break;
3192:
3193: case expr_arg:
3194: if (expr -> data.arg.val)
3195: expression_dereference (&expr -> data.arg.val,
3196: file, line);
3197: if (expr -> data.arg.next)
3198: expression_dereference (&expr -> data.arg.next,
3199: file, line);
3200: break;
3201:
3202: case expr_function:
3203: fundef_dereference (&expr -> data.func, file, line);
3204: break;
3205:
3206: /* No subexpressions. */
3207: case expr_leased_address:
3208: case expr_lease_time:
3209: case expr_filename:
3210: case expr_sname:
3211: case expr_const_int:
3212: case expr_check:
3213: case expr_option:
3214: case expr_hardware:
3215: case expr_exists:
3216: case expr_known:
3217: case expr_null:
3218: break;
3219:
3220: default:
3221: break;
3222: }
3223: free_expression (expr, MDL);
3224: }
3225:
3226: int is_dns_expression (expr)
3227: struct expression *expr;
3228: {
3229: return (expr -> op == expr_ns_add ||
3230: expr -> op == expr_ns_delete ||
3231: expr -> op == expr_ns_exists ||
3232: expr -> op == expr_ns_not_exists);
3233: }
3234:
3235: int is_boolean_expression (expr)
3236: struct expression *expr;
3237: {
3238: return (expr -> op == expr_check ||
3239: expr -> op == expr_exists ||
3240: expr -> op == expr_variable_exists ||
3241: expr -> op == expr_equal ||
3242: expr -> op == expr_not_equal ||
3243: expr->op == expr_regex_match ||
3244: expr->op == expr_iregex_match ||
3245: expr -> op == expr_and ||
3246: expr -> op == expr_or ||
3247: expr -> op == expr_not ||
3248: expr -> op == expr_known ||
3249: expr -> op == expr_static);
3250: }
3251:
3252: int is_data_expression (expr)
3253: struct expression *expr;
3254: {
3255: return (expr->op == expr_substring ||
3256: expr->op == expr_suffix ||
3257: expr->op == expr_lcase ||
3258: expr->op == expr_ucase ||
3259: expr->op == expr_option ||
3260: expr->op == expr_hardware ||
3261: expr->op == expr_const_data ||
3262: expr->op == expr_packet ||
3263: expr->op == expr_concat ||
3264: expr->op == expr_encapsulate ||
3265: expr->op == expr_encode_int8 ||
3266: expr->op == expr_encode_int16 ||
3267: expr->op == expr_encode_int32 ||
3268: expr->op == expr_host_lookup ||
3269: expr->op == expr_binary_to_ascii ||
3270: expr->op == expr_filename ||
3271: expr->op == expr_sname ||
3272: expr->op == expr_reverse ||
3273: expr->op == expr_pick_first_value ||
3274: expr->op == expr_host_decl_name ||
3275: expr->op == expr_leased_address ||
3276: expr->op == expr_config_option ||
3277: expr->op == expr_null);
3278: }
3279:
3280: int is_numeric_expression (expr)
3281: struct expression *expr;
3282: {
3283: return (expr -> op == expr_extract_int8 ||
3284: expr -> op == expr_extract_int16 ||
3285: expr -> op == expr_extract_int32 ||
3286: expr -> op == expr_const_int ||
3287: expr -> op == expr_lease_time ||
3288: expr -> op == expr_dns_transaction ||
3289: expr -> op == expr_add ||
3290: expr -> op == expr_subtract ||
3291: expr -> op == expr_multiply ||
3292: expr -> op == expr_divide ||
3293: expr -> op == expr_remainder ||
3294: expr -> op == expr_binary_and ||
3295: expr -> op == expr_binary_or ||
3296: expr -> op == expr_binary_xor ||
3297: expr -> op == expr_client_state);
3298: }
3299:
3300: int is_compound_expression (expr)
3301: struct expression *expr;
3302: {
3303: return (expr -> op == expr_ns_add ||
3304: expr -> op == expr_ns_delete ||
3305: expr -> op == expr_ns_exists ||
3306: expr -> op == expr_ns_not_exists ||
3307: expr -> op == expr_substring ||
3308: expr -> op == expr_suffix ||
3309: expr -> op == expr_option ||
3310: expr -> op == expr_concat ||
3311: expr -> op == expr_encode_int8 ||
3312: expr -> op == expr_encode_int16 ||
3313: expr -> op == expr_encode_int32 ||
3314: expr -> op == expr_binary_to_ascii ||
3315: expr -> op == expr_reverse ||
3316: expr -> op == expr_pick_first_value ||
3317: expr -> op == expr_config_option ||
3318: expr -> op == expr_extract_int8 ||
3319: expr -> op == expr_extract_int16 ||
3320: expr -> op == expr_extract_int32 ||
3321: expr -> op == expr_dns_transaction);
3322: }
3323:
3324: static int op_val (enum expr_op);
3325:
3326: static int op_val (op)
3327: enum expr_op op;
3328: {
3329: switch (op) {
3330: case expr_none:
3331: case expr_match:
3332: case expr_static:
3333: case expr_check:
3334: case expr_substring:
3335: case expr_suffix:
3336: case expr_lcase:
3337: case expr_ucase:
3338: case expr_concat:
3339: case expr_encapsulate:
3340: case expr_host_lookup:
3341: case expr_not:
3342: case expr_option:
3343: case expr_hardware:
3344: case expr_packet:
3345: case expr_const_data:
3346: case expr_extract_int8:
3347: case expr_extract_int16:
3348: case expr_extract_int32:
3349: case expr_encode_int8:
3350: case expr_encode_int16:
3351: case expr_encode_int32:
3352: case expr_const_int:
3353: case expr_exists:
3354: case expr_variable_exists:
3355: case expr_known:
3356: case expr_binary_to_ascii:
3357: case expr_reverse:
3358: case expr_filename:
3359: case expr_sname:
3360: case expr_pick_first_value:
3361: case expr_host_decl_name:
3362: case expr_config_option:
3363: case expr_leased_address:
3364: case expr_lease_time:
3365: case expr_dns_transaction:
3366: case expr_null:
3367: case expr_variable_reference:
3368: case expr_ns_add:
3369: case expr_ns_delete:
3370: case expr_ns_exists:
3371: case expr_ns_not_exists:
3372: case expr_arg:
3373: case expr_funcall:
3374: case expr_function:
3375: /* XXXDPN: Need to assign sane precedences to these. */
3376: case expr_binary_and:
3377: case expr_binary_or:
3378: case expr_binary_xor:
3379: case expr_client_state:
3380: return 100;
3381:
3382: case expr_equal:
3383: case expr_not_equal:
3384: case expr_regex_match:
3385: case expr_iregex_match:
3386: return 4;
3387:
3388: case expr_or:
3389: case expr_and:
3390: return 3;
3391:
3392: case expr_add:
3393: case expr_subtract:
3394: return 2;
3395:
3396: case expr_multiply:
3397: case expr_divide:
3398: case expr_remainder:
3399: return 1;
3400: }
3401: return 100;
3402: }
3403:
3404: int op_precedence (op1, op2)
3405: enum expr_op op1, op2;
3406: {
3407: return op_val (op1) - op_val (op2);
3408: }
3409:
3410: enum expression_context expression_context (struct expression *expr)
3411: {
3412: if (is_data_expression (expr))
3413: return context_data;
3414: if (is_numeric_expression (expr))
3415: return context_numeric;
3416: if (is_boolean_expression (expr))
3417: return context_boolean;
3418: if (is_dns_expression (expr))
3419: return context_dns;
3420: return context_any;
3421: }
3422:
3423: enum expression_context op_context (op)
3424: enum expr_op op;
3425: {
3426: switch (op) {
3427: /* XXX Why aren't these specific? */
3428: case expr_none:
3429: case expr_match:
3430: case expr_static:
3431: case expr_check:
3432: case expr_substring:
3433: case expr_suffix:
3434: case expr_lcase:
3435: case expr_ucase:
3436: case expr_concat:
3437: case expr_encapsulate:
3438: case expr_host_lookup:
3439: case expr_not:
3440: case expr_option:
3441: case expr_hardware:
3442: case expr_packet:
3443: case expr_const_data:
3444: case expr_extract_int8:
3445: case expr_extract_int16:
3446: case expr_extract_int32:
3447: case expr_encode_int8:
3448: case expr_encode_int16:
3449: case expr_encode_int32:
3450: case expr_const_int:
3451: case expr_exists:
3452: case expr_variable_exists:
3453: case expr_known:
3454: case expr_binary_to_ascii:
3455: case expr_reverse:
3456: case expr_filename:
3457: case expr_sname:
3458: case expr_pick_first_value:
3459: case expr_host_decl_name:
3460: case expr_config_option:
3461: case expr_leased_address:
3462: case expr_lease_time:
3463: case expr_null:
3464: case expr_variable_reference:
3465: case expr_ns_add:
3466: case expr_ns_delete:
3467: case expr_ns_exists:
3468: case expr_ns_not_exists:
3469: case expr_dns_transaction:
3470: case expr_arg:
3471: case expr_funcall:
3472: case expr_function:
3473: return context_any;
3474:
3475: case expr_equal:
3476: case expr_not_equal:
3477: case expr_regex_match:
3478: case expr_iregex_match:
3479: return context_data;
3480:
3481: case expr_and:
3482: return context_boolean;
3483:
3484: case expr_or:
3485: return context_boolean;
3486:
3487: case expr_add:
3488: case expr_subtract:
3489: case expr_multiply:
3490: case expr_divide:
3491: case expr_remainder:
3492: case expr_binary_and:
3493: case expr_binary_or:
3494: case expr_binary_xor:
3495: case expr_client_state:
3496: return context_numeric;
3497: }
3498: return context_any;
3499: }
3500:
3501: int write_expression (file, expr, col, indent, firstp)
3502: FILE *file;
3503: struct expression *expr;
3504: int col;
3505: int indent;
3506: int firstp;
3507: {
3508: struct expression *e;
3509: const char *s;
3510: char obuf [65];
3511: int scol;
3512: int width;
3513:
3514: /* If this promises to be a fat expression, start a new line. */
3515: if (!firstp && is_compound_expression (expr)) {
3516: indent_spaces (file, indent);
3517: col = indent;
3518: }
3519:
3520: switch (expr -> op) {
3521: case expr_none:
3522: col = token_print_indent (file, col, indent, "", "", "null");
3523: break;
3524:
3525: case expr_check:
3526: col = token_print_indent (file, col, indent, "", "", "check");
3527: col = token_print_indent_concat (file, col, indent,
3528: " ", "", "\"",
3529: expr -> data.check -> name,
3530: "\"", (char *)0);
3531: break;
3532:
3533: case expr_regex_match:
3534: s = "~=";
3535: goto binary;
3536:
3537: case expr_iregex_match:
3538: s = "~~";
3539: goto binary;
3540:
3541: case expr_not_equal:
3542: s = "!=";
3543: goto binary;
3544:
3545: case expr_equal:
3546: s = "=";
3547: binary:
3548: col = write_expression (file, expr -> data.equal [0],
3549: col, indent, 1);
3550: col = token_print_indent (file, col, indent, " ", " ", s);
3551: col = write_expression (file, expr -> data.equal [1],
3552: col, indent + 2, 0);
3553: break;
3554:
3555: case expr_substring:
3556: col = token_print_indent (file, col, indent, "", "",
3557: "substring");
3558: col = token_print_indent (file, col, indent, " ", "", "(");
3559: scol = col;
3560: col = write_expression (file, expr -> data.substring.expr,
3561: col, scol, 1);
3562: col = token_print_indent (file, col, indent, "", " ", ",");
3563: col = write_expression (file, expr -> data.substring.offset,
3564: col, indent, 0);
3565: col = token_print_indent (file, col, scol, "", " ", ",");
3566: col = write_expression (file, expr -> data.substring.len,
3567: col, scol, 0);
3568: col = token_print_indent (file, col, indent, "", "", ")");
3569: break;
3570:
3571: case expr_suffix:
3572: col = token_print_indent (file, col, indent, "", "", "suffix");
3573: col = token_print_indent (file, col, indent, " ", "", "(");
3574: scol = col;
3575: col = write_expression (file, expr -> data.suffix.expr,
3576: col, scol, 1);
3577: col = token_print_indent (file, col, scol, "", " ", ",");
3578: col = write_expression (file, expr -> data.suffix.len,
3579: col, scol, 0);
3580: col = token_print_indent (file, col, indent, "", "", ")");
3581:
3582: case expr_lcase:
3583: col = token_print_indent(file, col, indent, "", "", "lcase");
3584: col = token_print_indent(file, col, indent, " ", "", "(");
3585: scol = col;
3586: col = write_expression(file, expr->data.lcase, col, scol, 1);
3587: col = token_print_indent(file, col, indent, "", "", ")");
3588: break;
3589:
3590: case expr_ucase:
3591: col = token_print_indent(file, col, indent, "", "", "ucase");
3592: col = token_print_indent(file, col, indent, " ", "", "(");
3593: scol = col;
3594: col = write_expression(file, expr->data.ucase, col, scol, 1);
3595: col = token_print_indent(file, col, indent, "", "", ")");
3596: break;
3597:
3598: case expr_concat:
3599: e = expr;
3600: col = token_print_indent (file, col, indent, "", "",
3601: "concat");
3602: col = token_print_indent (file, col, indent, " ", "", "(");
3603: scol = col;
3604: firstp = 1;
3605: concat_again:
3606: col = write_expression (file, e -> data.concat [0],
3607: col, scol, firstp);
3608: firstp = 0;
3609: if (!e -> data.concat [1])
3610: goto no_concat_cdr;
3611: col = token_print_indent (file, col, scol, "", " ", ",");
3612: if (e -> data.concat [1] -> op == expr_concat) {
3613: e = e -> data.concat [1];
3614: goto concat_again;
3615: }
3616: col = write_expression (file, e -> data.concat [1],
3617: col, scol, 0);
3618: no_concat_cdr:
3619: col = token_print_indent (file, col, indent, "", "", ")");
3620: break;
3621:
3622: case expr_host_lookup:
3623: col = token_print_indent (file, col, indent, "", "",
3624: "gethostbyname");
3625: col = token_print_indent (file, col, indent, " ", "", "(");
3626: col = token_print_indent_concat
3627: (file, col, indent, "", "",
3628: "\"", expr -> data.host_lookup -> hostname, "\"",
3629: (char *)0);
3630: col = token_print_indent (file, col, indent, "", "", ")");
3631: break;
3632:
3633: case expr_add:
3634: s = "+";
3635: goto binary;
3636:
3637: case expr_subtract:
3638: s = "-";
3639: goto binary;
3640:
3641: case expr_multiply:
3642: s = "*";
3643: goto binary;
3644:
3645: case expr_divide:
3646: s = "/";
3647: goto binary;
3648:
3649: case expr_remainder:
3650: s = "%";
3651: goto binary;
3652:
3653: case expr_binary_and:
3654: s = "&";
3655: goto binary;
3656:
3657: case expr_binary_or:
3658: s = "|";
3659: goto binary;
3660:
3661: case expr_binary_xor:
3662: s = "^";
3663: goto binary;
3664:
3665: case expr_and:
3666: s = "and";
3667: goto binary;
3668:
3669: case expr_or:
3670: s = "or";
3671: goto binary;
3672:
3673: case expr_not:
3674: col = token_print_indent (file, col, indent, "", " ", "not");
3675: col = write_expression (file,
3676: expr -> data.not, col, indent + 2, 1);
3677: break;
3678:
3679: case expr_option:
3680: s = "option";
3681:
3682: print_option_name:
3683: col = token_print_indent (file, col, indent, "", "", s);
3684:
3685: if (expr -> data.option -> universe != &dhcp_universe) {
3686: col = token_print_indent (file, col, indent,
3687: " ", "",
3688: (expr -> data.option ->
3689: universe -> name));
3690: col = token_print_indent (file, col, indent, "", "",
3691: ".");
3692: col = token_print_indent (file, col, indent, "", "",
3693: expr -> data.option -> name);
3694: } else {
3695: col = token_print_indent (file, col, indent, " ", "",
3696: expr -> data.option -> name);
3697: }
3698: break;
3699:
3700: case expr_hardware:
3701: col = token_print_indent (file, col, indent, "", "",
3702: "hardware");
3703: break;
3704:
3705: case expr_packet:
3706: col = token_print_indent (file, col, indent, "", "",
3707: "packet");
3708: col = token_print_indent (file, col, indent, " ", "", "(");
3709: scol = col;
3710: col = write_expression (file, expr -> data.packet.offset,
3711: col, indent, 1);
3712: col = token_print_indent (file, col, scol, "", " ", ",");
3713: col = write_expression (file, expr -> data.packet.len,
3714: col, scol, 0);
3715: col = token_print_indent (file, col, indent, "", "", ")");
3716: break;
3717:
3718: case expr_const_data:
3719: col = token_indent_data_string (file, col, indent, "", "",
3720: &expr -> data.const_data);
3721: break;
3722:
3723: case expr_extract_int8:
3724: width = 8;
3725: extract_int:
3726: col = token_print_indent (file, col, indent, "", "",
3727: "extract-int");
3728: col = token_print_indent (file, col, indent, " ", "", "(");
3729: scol = col;
3730: col = write_expression (file, expr -> data.extract_int,
3731: col, indent, 1);
3732: col = token_print_indent (file, col, scol, "", " ", ",");
3733: sprintf (obuf, "%d", width);
3734: col = token_print_indent (file, col, scol, " ", "", obuf);
3735: col = token_print_indent (file, col, indent, "", "", ")");
3736: break;
3737:
3738: case expr_extract_int16:
3739: width = 16;
3740: goto extract_int;
3741:
3742: case expr_extract_int32:
3743: width = 32;
3744: goto extract_int;
3745:
3746: case expr_encode_int8:
3747: width = 8;
3748: encode_int:
3749: col = token_print_indent (file, col, indent, "", "",
3750: "encode-int");
3751: col = token_print_indent (file, col, indent, " ", "", "(");
3752: scol = col;
3753: col = write_expression (file, expr -> data.extract_int,
3754: col, indent, 1);
3755: col = token_print_indent (file, col, scol, "", " ", ",");
3756: sprintf (obuf, "%d", width);
3757: col = token_print_indent (file, col, scol, " ", "", obuf);
3758: col = token_print_indent (file, col, indent, "", "",
3759: ")");
3760: break;
3761:
3762: case expr_encode_int16:
3763: width = 16;
3764: goto encode_int;
3765:
3766: case expr_encode_int32:
3767: width = 32;
3768: goto encode_int;
3769:
3770: case expr_const_int:
3771: sprintf (obuf, "%lu", expr -> data.const_int);
3772: col = token_print_indent (file, col, indent, "", "", obuf);
3773: break;
3774:
3775: case expr_exists:
3776: s = "exists";
3777: goto print_option_name;
3778:
3779: case expr_encapsulate:
3780: col = token_print_indent (file, col, indent, "", "",
3781: "encapsulate");
3782: col = token_indent_data_string (file, col, indent, " ", "",
3783: &expr -> data.encapsulate);
3784: break;
3785:
3786: case expr_known:
3787: col = token_print_indent (file, col, indent, "", "", "known");
3788: break;
3789:
3790: case expr_reverse:
3791: col = token_print_indent (file, col, indent, "", "",
3792: "reverse");
3793: col = token_print_indent (file, col, indent, " ", "", "(");
3794: scol = col;
3795: col = write_expression (file, expr -> data.reverse.width,
3796: col, scol, 1);
3797: col = token_print_indent (file, col, scol, "", " ", ",");
3798: col = write_expression (file, expr -> data.reverse.buffer,
3799: col, scol, 0);
3800: col = token_print_indent (file, col, indent, "", "",
3801: ")");
3802: break;
3803:
3804: case expr_leased_address:
3805: col = token_print_indent (file, col, indent, "", "",
3806: "leased-address");
3807: break;
3808:
3809: case expr_client_state:
3810: col = token_print_indent (file, col, indent, "", "",
3811: "client-state");
3812: break;
3813:
3814: case expr_binary_to_ascii:
3815: col = token_print_indent (file, col, indent, "", "",
3816: "binary-to-ascii");
3817: col = token_print_indent (file, col, indent, " ", "",
3818: "(");
3819: scol = col;
3820: col = write_expression (file, expr -> data.b2a.base,
3821: col, scol, 1);
3822: col = token_print_indent (file, col, scol, "", " ",
3823: ",");
3824: col = write_expression (file, expr -> data.b2a.width,
3825: col, scol, 0);
3826: col = token_print_indent (file, col, scol, "", " ",
3827: ",");
3828: col = write_expression (file, expr -> data.b2a.separator,
3829: col, scol, 0);
3830: col = token_print_indent (file, col, scol, "", " ",
3831: ",");
3832: col = write_expression (file, expr -> data.b2a.buffer,
3833: col, scol, 0);
3834: col = token_print_indent (file, col, indent, "", "",
3835: ")");
3836: break;
3837:
3838: case expr_config_option:
3839: s = "config-option";
3840: goto print_option_name;
3841:
3842: case expr_host_decl_name:
3843: col = token_print_indent (file, col, indent, "", "",
3844: "host-decl-name");
3845: break;
3846:
3847: case expr_pick_first_value:
3848: e = expr;
3849: col = token_print_indent (file, col, indent, "", "",
3850: "concat");
3851: col = token_print_indent (file, col, indent, " ", "",
3852: "(");
3853: scol = col;
3854: firstp = 1;
3855: pick_again:
3856: col = write_expression (file,
3857: e -> data.pick_first_value.car,
3858: col, scol, firstp);
3859: firstp = 0;
3860: /* We're being very lisp-like right now - instead of
3861: representing this expression as (first middle . last) we're
3862: representing it as (first middle last), which means that the
3863: tail cdr is always nil. Apologies to non-wisp-lizards - may
3864: this obscure way of describing the problem motivate you to
3865: learn more about the one true computing language. */
3866: if (!e -> data.pick_first_value.cdr)
3867: goto no_pick_cdr;
3868: col = token_print_indent (file, col, scol, "", " ",
3869: ",");
3870: if (e -> data.pick_first_value.cdr -> op ==
3871: expr_pick_first_value) {
3872: e = e -> data.pick_first_value.cdr;
3873: goto pick_again;
3874: }
3875: col = write_expression (file,
3876: e -> data.pick_first_value.cdr,
3877: col, scol, 0);
3878: no_pick_cdr:
3879: col = token_print_indent (file, col, indent, "", "",
3880: ")");
3881: break;
3882:
3883: case expr_lease_time:
3884: col = token_print_indent (file, col, indent, "", "",
3885: "lease-time");
3886: break;
3887:
3888: case expr_dns_transaction:
3889: col = token_print_indent (file, col, indent, "", "",
3890: "ns-update");
3891: col = token_print_indent (file, col, indent, " ", "",
3892: "(");
3893: scol = 0;
3894: for (e = expr;
3895: e && e -> op == expr_dns_transaction;
3896: e = e -> data.dns_transaction.cdr) {
3897: if (!scol) {
3898: scol = col;
3899: firstp = 1;
3900: } else
3901: firstp = 0;
3902: col = write_expression (file,
3903: e -> data.dns_transaction.car,
3904: col, scol, firstp);
3905: if (e -> data.dns_transaction.cdr)
3906: col = token_print_indent (file, col, scol,
3907: "", " ", ",");
3908: }
3909: if (e)
3910: col = write_expression (file, e, col, scol, 0);
3911: col = token_print_indent (file, col, indent, "", "", ")");
3912: break;
3913:
3914: case expr_ns_add:
3915: col = token_print_indent (file, col, indent, "", "",
3916: "update");
3917: col = token_print_indent (file, col, indent, " ", "",
3918: "(");
3919: scol = col;
3920: sprintf (obuf, "%d", expr -> data.ns_add.rrclass);
3921: col = token_print_indent (file, col, scol, "", "", obuf);
3922: col = token_print_indent (file, col, scol, "", " ",
3923: ",");
3924: sprintf (obuf, "%d", expr -> data.ns_add.rrtype);
3925: col = token_print_indent (file, col, scol, "", "", obuf);
3926: col = token_print_indent (file, col, scol, "", " ",
3927: ",");
3928: col = write_expression (file, expr -> data.ns_add.rrname,
3929: col, scol, 0);
3930: col = token_print_indent (file, col, scol, "", " ",
3931: ",");
3932: col = write_expression (file, expr -> data.ns_add.rrdata,
3933: col, scol, 0);
3934: col = token_print_indent (file, col, scol, "", " ",
3935: ",");
3936: col = write_expression (file, expr -> data.ns_add.ttl,
3937: col, scol, 0);
3938: col = token_print_indent (file, col, indent, "", "",
3939: ")");
3940: break;
3941:
3942: case expr_ns_delete:
3943: col = token_print_indent (file, col, indent, "", "",
3944: "delete");
3945: col = token_print_indent (file, col, indent, " ", "",
3946: "(");
3947: finish_ns_small:
3948: scol = col;
3949: sprintf (obuf, "%d", expr -> data.ns_add.rrclass);
3950: col = token_print_indent (file, col, scol, "", "", obuf);
3951: col = token_print_indent (file, col, scol, "", " ",
3952: ",");
3953: sprintf (obuf, "%d", expr -> data.ns_add.rrtype);
3954: col = token_print_indent (file, col, scol, "", "", obuf);
3955: col = token_print_indent (file, col, scol, "", " ",
3956: ",");
3957: col = write_expression (file, expr -> data.ns_add.rrname,
3958: col, scol, 0);
3959: col = token_print_indent (file, col, scol, "", " ",
3960: ",");
3961: col = write_expression (file, expr -> data.ns_add.rrdata,
3962: col, scol, 0);
3963: col = token_print_indent (file, col, indent, "", "",
3964: ")");
3965: break;
3966:
3967: case expr_ns_exists:
3968: col = token_print_indent (file, col, indent, "", "",
3969: "exists");
3970: col = token_print_indent (file, col, indent, " ", "",
3971: "(");
3972: goto finish_ns_small;
3973:
3974: case expr_ns_not_exists:
3975: col = token_print_indent (file, col, indent, "", "",
3976: "not exists");
3977: col = token_print_indent (file, col, indent, " ", "",
3978: "(");
3979: goto finish_ns_small;
3980:
3981: case expr_static:
3982: col = token_print_indent (file, col, indent, "", "",
3983: "static");
3984: break;
3985:
3986: case expr_null:
3987: col = token_print_indent (file, col, indent, "", "", "null");
3988: break;
3989:
3990: case expr_variable_reference:
3991: col = token_print_indent (file, indent, indent, "", "",
3992: expr -> data.variable);
3993: break;
3994:
3995: case expr_variable_exists:
3996: col = token_print_indent (file, indent, indent, "", "",
3997: "defined");
3998: col = token_print_indent (file, col, indent, " ", "", "(");
3999: col = token_print_indent (file, col, indent, "", "",
4000: expr -> data.variable);
4001: col = token_print_indent (file, col, indent, "", "", ")");
4002: break;
4003:
4004: case expr_funcall:
4005: col = token_print_indent(file, indent, indent, "", "",
4006: expr->data.funcall.name);
4007: col = token_print_indent(file, col, indent, " ", "", "(");
4008:
4009: firstp = 1;
4010: e = expr->data.funcall.arglist;
4011: while (e != NULL) {
4012: if (!firstp)
4013: col = token_print_indent(file, col, indent,
4014: "", " ", ",");
4015:
4016: col = write_expression(file, e->data.arg.val, col,
4017: indent, firstp);
4018: firstp = 0;
4019: e = e->data.arg.next;
4020: }
4021:
4022: col = token_print_indent(file, col, indent, "", "", ")");
4023: break;
4024:
4025: default:
4026: log_fatal ("invalid expression type in print_expression: %d",
4027: expr -> op);
4028: }
4029: return col;
4030: }
4031:
4032: struct binding *find_binding (struct binding_scope *scope, const char *name)
4033: {
4034: struct binding *bp;
4035: struct binding_scope *s;
4036:
4037: for (s = scope; s; s = s -> outer) {
4038: for (bp = s -> bindings; bp; bp = bp -> next) {
4039: if (!strcasecmp (name, bp -> name)) {
4040: return bp;
4041: }
4042: }
4043: }
4044: return (struct binding *)0;
4045: }
4046:
4047: int free_bindings (struct binding_scope *scope, const char *file, int line)
4048: {
4049: struct binding *bp, *next;
4050:
4051: for (bp = scope -> bindings; bp; bp = next) {
4052: next = bp -> next;
4053: if (bp -> name)
4054: dfree (bp -> name, file, line);
4055: if (bp -> value)
4056: binding_value_dereference (&bp -> value, file, line);
4057: dfree (bp, file, line);
4058: }
4059: scope -> bindings = (struct binding *)0;
4060: return 1;
4061: }
4062:
4063: int binding_scope_dereference (ptr, file, line)
4064: struct binding_scope **ptr;
4065: const char *file;
4066: int line;
4067: {
4068: struct binding_scope *binding_scope;
4069:
4070: if (!ptr || !*ptr) {
4071: log_error ("%s(%d): null pointer", file, line);
4072: #if defined (POINTER_DEBUG)
4073: abort ();
4074: #else
4075: return 0;
4076: #endif
4077: }
4078:
4079: binding_scope = *ptr;
4080: *ptr = (struct binding_scope *)0;
4081: --binding_scope -> refcnt;
4082: rc_register (file, line, ptr,
4083: binding_scope, binding_scope -> refcnt, 1, RC_MISC);
4084: if (binding_scope -> refcnt > 0)
4085: return 1;
4086:
4087: if (binding_scope -> refcnt < 0) {
4088: log_error ("%s(%d): negative refcnt!", file, line);
4089: #if defined (DEBUG_RC_HISTORY)
4090: dump_rc_history (binding_scope);
4091: #endif
4092: #if defined (POINTER_DEBUG)
4093: abort ();
4094: #else
4095: return 0;
4096: #endif
4097: }
4098:
4099: free_bindings (binding_scope, file, line);
4100: if (binding_scope -> outer)
4101: binding_scope_dereference (&binding_scope -> outer, MDL);
4102: dfree (binding_scope, file, line);
4103: return 1;
4104: }
4105:
4106: int fundef_dereference (ptr, file, line)
4107: struct fundef **ptr;
4108: const char *file;
4109: int line;
4110: {
4111: struct fundef *bp = *ptr;
4112: struct string_list *sp, *next;
4113:
4114: if (!ptr) {
4115: log_error ("%s(%d): null pointer", file, line);
4116: #if defined (POINTER_DEBUG)
4117: abort ();
4118: #else
4119: return 0;
4120: #endif
4121: }
4122:
4123: if (!bp) {
4124: log_error ("%s(%d): null pointer", file, line);
4125: #if defined (POINTER_DEBUG)
4126: abort ();
4127: #else
4128: return 0;
4129: #endif
4130: }
4131:
4132: bp -> refcnt--;
4133: rc_register (file, line, ptr, bp, bp -> refcnt, 1, RC_MISC);
4134: if (bp -> refcnt < 0) {
4135: log_error ("%s(%d): negative refcnt!", file, line);
4136: #if defined (DEBUG_RC_HISTORY)
4137: dump_rc_history (bp);
4138: #endif
4139: #if defined (POINTER_DEBUG)
4140: abort ();
4141: #else
4142: return 0;
4143: #endif
4144: }
4145: if (!bp -> refcnt) {
4146: for (sp = bp -> args; sp; sp = next) {
4147: next = sp -> next;
4148: dfree (sp, file, line);
4149: }
4150: if (bp -> statements)
4151: executable_statement_dereference (&bp -> statements,
4152: file, line);
4153: dfree (bp, file, line);
4154: }
4155: *ptr = (struct fundef *)0;
4156: return 1;
4157: }
4158:
4159: #if defined (NOTYET) /* Post 3.0 final. */
4160: int data_subexpression_length (int *rv,
4161: struct expression *expr)
4162: {
4163: int crhs, clhs, llhs, lrhs;
4164: switch (expr -> op) {
4165: case expr_substring:
4166: if (expr -> data.substring.len &&
4167: expr -> data.substring.len -> op == expr_const_int) {
4168: (*rv =
4169: (int)expr -> data.substring.len -> data.const_int);
4170: return 1;
4171: }
4172: return 0;
4173:
4174: case expr_packet:
4175: case expr_suffix:
4176: if (expr -> data.suffix.len &&
4177: expr -> data.suffix.len -> op == expr_const_int) {
4178: (*rv =
4179: (int)expr -> data.suffix.len -> data.const_int);
4180: return 1;
4181: }
4182: return 0;
4183:
4184: case expr_lcase:
4185: return data_subexpression_length(rv, expr->data.lcase);
4186:
4187: case expr_ucase:
4188: return data_subexpression_length(rv, expr->data.ucase);
4189:
4190: case expr_concat:
4191: clhs = data_subexpression_length (&llhs,
4192: expr -> data.concat [0]);
4193: crhs = data_subexpression_length (&lrhs,
4194: expr -> data.concat [1]);
4195: if (crhs == 0 || clhs == 0)
4196: return 0;
4197: *rv = llhs + lrhs;
4198: return 1;
4199: break;
4200:
4201: case expr_hardware:
4202: return 0;
4203:
4204: case expr_const_data:
4205: *rv = expr -> data.const_data.len;
4206: return 2;
4207:
4208: case expr_reverse:
4209: return data_subexpression_length (rv,
4210: expr -> data.reverse.buffer);
4211:
4212: case expr_leased_address:
4213: case expr_lease_time:
4214: *rv = 4;
4215: return 2;
4216:
4217: case expr_pick_first_value:
4218: clhs = data_subexpression_length (&llhs,
4219: expr -> data.concat [0]);
4220: crhs = data_subexpression_length (&lrhs,
4221: expr -> data.concat [1]);
4222: if (crhs == 0 || clhs == 0)
4223: return 0;
4224: if (llhs > lrhs)
4225: *rv = llhs;
4226: else
4227: *rv = lrhs;
4228: return 1;
4229:
4230: case expr_binary_to_ascii:
4231: case expr_config_option:
4232: case expr_host_decl_name:
4233: case expr_encapsulate:
4234: case expr_filename:
4235: case expr_sname:
4236: case expr_host_lookup:
4237: case expr_option:
4238: case expr_none:
4239: case expr_match:
4240: case expr_check:
4241: case expr_equal:
4242: case expr_regex_match:
4243: case expr_iregex_match:
4244: case expr_and:
4245: case expr_or:
4246: case expr_not:
4247: case expr_extract_int8:
4248: case expr_extract_int16:
4249: case expr_extract_int32:
4250: case expr_encode_int8:
4251: case expr_encode_int16:
4252: case expr_encode_int32:
4253: case expr_const_int:
4254: case expr_exists:
4255: case expr_known:
4256: case expr_dns_transaction:
4257: case expr_static:
4258: case expr_ns_add:
4259: case expr_ns_delete:
4260: case expr_ns_exists:
4261: case expr_ns_not_exists:
4262: case expr_not_equal:
4263: case expr_null:
4264: case expr_variable_exists:
4265: case expr_variable_reference:
4266: case expr_arg:
4267: case expr_funcall:
4268: case expr_function:
4269: case expr_add:
4270: case expr_subtract:
4271: case expr_multiply:
4272: case expr_divide:
4273: case expr_remainder:
4274: case expr_binary_and:
4275: case expr_binary_or:
4276: case expr_binary_xor:
4277: case expr_client_state:
4278: return 0;
4279: }
4280: return 0;
4281: }
4282:
4283: int expr_valid_for_context (struct expression *expr,
4284: enum expression_context context)
4285: {
4286: /* We don't know at parse time what type of value a function may
4287: return, so we can't flag an error on it. */
4288: if (expr -> op == expr_funcall ||
4289: expr -> op == expr_variable_reference)
4290: return 1;
4291:
4292: switch (context) {
4293: case context_any:
4294: return 1;
4295:
4296: case context_boolean:
4297: if (is_boolean_expression (expr))
4298: return 1;
4299: return 0;
4300:
4301: case context_data:
4302: if (is_data_expression (expr))
4303: return 1;
4304: return 0;
4305:
4306: case context_numeric:
4307: if (is_numeric_expression (expr))
4308: return 1;
4309: return 0;
4310:
4311: case context_dns:
4312: if (is_dns_expression (expr)) {
4313: return 1;
4314: }
4315: return 0;
4316:
4317: case context_data_or_numeric:
4318: if (is_numeric_expression (expr) ||
4319: is_data_expression (expr)) {
4320: return 1;
4321: }
4322: return 0;
4323:
4324: case context_function:
4325: if (expr -> op == expr_function)
4326: return 1;
4327: return 0;
4328: }
4329: return 0;
4330: }
4331: #endif /* NOTYET */
4332:
4333: struct binding *create_binding (struct binding_scope **scope, const char *name)
4334: {
4335: struct binding *binding;
4336:
4337: if (!*scope) {
4338: if (!binding_scope_allocate (scope, MDL))
4339: return (struct binding *)0;
4340: }
4341:
4342: binding = find_binding (*scope, name);
4343: if (!binding) {
4344: binding = dmalloc (sizeof *binding, MDL);
4345: if (!binding)
4346: return (struct binding *)0;
4347:
4348: memset (binding, 0, sizeof *binding);
4349: binding -> name = dmalloc (strlen (name) + 1, MDL);
4350: if (!binding -> name) {
4351: dfree (binding, MDL);
4352: return (struct binding *)0;
4353: }
4354: strcpy (binding -> name, name);
4355:
4356: binding -> next = (*scope) -> bindings;
4357: (*scope) -> bindings = binding;
4358: }
4359:
4360: return binding;
4361: }
4362:
4363:
4364: int bind_ds_value (struct binding_scope **scope,
4365: const char *name,
4366: struct data_string *value)
4367: {
4368: struct binding *binding;
4369:
4370: binding = create_binding (scope, name);
4371: if (!binding)
4372: return 0;
4373:
4374: if (binding -> value)
4375: binding_value_dereference (&binding -> value, MDL);
4376:
4377: if (!binding_value_allocate (&binding -> value, MDL))
4378: return 0;
4379:
4380: data_string_copy (&binding -> value -> value.data, value, MDL);
4381: binding -> value -> type = binding_data;
4382:
4383: return 1;
4384: }
4385:
4386:
4387: int find_bound_string (struct data_string *value,
4388: struct binding_scope *scope,
4389: const char *name)
4390: {
4391: struct binding *binding;
4392:
4393: binding = find_binding (scope, name);
4394: if (!binding ||
4395: !binding -> value ||
4396: binding -> value -> type != binding_data)
4397: return 0;
4398:
4399: if (binding -> value -> value.data.terminated) {
4400: data_string_copy (value, &binding -> value -> value.data, MDL);
4401: } else {
4402: buffer_allocate (&value -> buffer,
4403: binding -> value -> value.data.len,
4404: MDL);
4405: if (!value -> buffer)
4406: return 0;
4407:
4408: memcpy (value -> buffer -> data,
4409: binding -> value -> value.data.data,
4410: binding -> value -> value.data.len);
4411: value -> data = value -> buffer -> data;
4412: value -> len = binding -> value -> value.data.len;
4413: }
4414:
4415: return 1;
4416: }
4417:
4418: int unset (struct binding_scope *scope, const char *name)
4419: {
4420: struct binding *binding;
4421:
4422: binding = find_binding (scope, name);
4423: if (binding) {
4424: if (binding -> value)
4425: binding_value_dereference
4426: (&binding -> value, MDL);
4427: return 1;
4428: }
4429: return 0;
4430: }
4431:
4432: /* vim: set tabstop=8: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>