xref: /netbsd-src/external/mpl/dhcp/dist/common/execute.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: execute.c,v 1.2 2018/04/07 22:37:29 christos Exp $	*/
2 
3 /* execute.c
4 
5    Support for executable statements. */
6 
7 /*
8  * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
9  * Copyright (c) 1998-2003 by Internet Software Consortium
10  *
11  * This Source Code Form is subject to the terms of the Mozilla Public
12  * License, v. 2.0. If a copy of the MPL was not distributed with this
13  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
18  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  *   Internet Systems Consortium, Inc.
24  *   950 Charter Street
25  *   Redwood City, CA 94063
26  *   <info@isc.org>
27  *   https://www.isc.org/
28  *
29  */
30 
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: execute.c,v 1.2 2018/04/07 22:37:29 christos Exp $");
33 
34 #include "dhcpd.h"
35 #include <isc/util.h>
36 #include <omapip/omapip_p.h>
37 #include <sys/types.h>
38 #include <sys/wait.h>
39 
40 int execute_statements (result, packet, lease, client_state,
41 			in_options, out_options, scope, statements,
42 			on_star)
43 	struct binding_value **result;
44 	struct packet *packet;
45 	struct lease *lease;
46 	struct client_state *client_state;
47 	struct option_state *in_options;
48 	struct option_state *out_options;
49 	struct binding_scope **scope;
50 	struct executable_statement *statements;
51 	struct on_star *on_star;
52 {
53 	struct executable_statement *r, *e, *next;
54 	int rc;
55 	int status;
56 	struct binding *binding;
57 	struct data_string ds;
58 	struct binding_scope *ns;
59 
60 	if (!statements)
61 		return 1;
62 
63 	r = NULL;
64 	next = NULL;
65 	e = NULL;
66 	executable_statement_reference (&r, statements, MDL);
67 	while (r && !(result && *result)) {
68 		if (r->next)
69 			executable_statement_reference (&next, r->next, MDL);
70 		switch (r->op) {
71 		      case statements_statement:
72 #if defined (DEBUG_EXPRESSIONS)
73 			log_debug ("exec: statements");
74 #endif
75 			status = execute_statements (result, packet, lease,
76 						     client_state, in_options,
77 						     out_options, scope,
78 						     r->data.statements,
79 						     on_star);
80 #if defined (DEBUG_EXPRESSIONS)
81 			log_debug ("exec: statements returns %d", status);
82 #endif
83 			if (!status)
84 				return 0;
85 			break;
86 
87 		      case on_statement:
88 			/*
89 			 * if we haven't been passed an on_star block but
90 			 * do have a lease, use the one from the lease
91 			 * This handles the previous v4 calls.
92 			 */
93 			if ((on_star == NULL) && (lease != NULL))
94 			    on_star = &lease->on_star;
95 
96 			if (on_star != NULL) {
97 			    if (r->data.on.evtypes & ON_EXPIRY) {
98 #if defined (DEBUG_EXPRESSIONS)
99 				    log_debug ("exec: on expiry");
100 #endif
101 				if (on_star->on_expiry)
102 					executable_statement_dereference
103 						(&on_star->on_expiry, MDL);
104 				if (r->data.on.statements)
105 					executable_statement_reference
106 						(&on_star->on_expiry,
107 						 r->data.on.statements, MDL);
108 			    }
109 			    if (r->data.on.evtypes & ON_RELEASE) {
110 #if defined (DEBUG_EXPRESSIONS)
111 				    log_debug ("exec: on release");
112 #endif
113 				if (on_star->on_release)
114 					executable_statement_dereference
115 						(&on_star->on_release, MDL);
116 				if (r->data.on.statements)
117 					executable_statement_reference
118 						(&on_star->on_release,
119 						 r->data.on.statements, MDL);
120 			    }
121 			    if (r->data.on.evtypes & ON_COMMIT) {
122 #if defined (DEBUG_EXPRESSIONS)
123 				    log_debug ("exec: on commit");
124 #endif
125 				if (on_star->on_commit)
126 					executable_statement_dereference
127 						(&on_star->on_commit, MDL);
128 				if (r->data.on.statements)
129 					executable_statement_reference
130 						(&on_star->on_commit,
131 						 r->data.on.statements, MDL);
132 			    }
133 			}
134 			break;
135 
136 		      case switch_statement:
137 #if defined (DEBUG_EXPRESSIONS)
138 			log_debug ("exec: switch");
139 #endif
140 			status = (find_matching_case
141 				  (&e, packet, lease, client_state,
142 				   in_options, out_options, scope,
143 				   r->data.s_switch.expr,
144 				   r->data.s_switch.statements));
145 #if defined (DEBUG_EXPRESSIONS)
146 			log_debug ("exec: switch: case %lx", (unsigned long)e);
147 #endif
148 			if (status) {
149 				if (!(execute_statements
150 				      (result, packet, lease, client_state,
151 				       in_options, out_options, scope, e,
152 				       on_star))) {
153 					executable_statement_dereference
154 						(&e, MDL);
155 					return 0;
156 				}
157 				executable_statement_dereference (&e, MDL);
158 			}
159 			break;
160 
161 			/* These have no effect when executed. */
162 		      case case_statement:
163 		      case default_statement:
164 			break;
165 
166 		      case if_statement:
167 			status = (evaluate_boolean_expression
168 				  (&rc, packet,
169 				   lease, client_state, in_options,
170 				   out_options, scope, r->data.ie.expr));
171 
172 #if defined (DEBUG_EXPRESSIONS)
173 			log_debug ("exec: if %s", (status
174 					      ? (rc ? "true" : "false")
175 					      : "NULL"));
176 #endif
177 			/* XXX Treat NULL as false */
178 			if (!status)
179 				rc = 0;
180 			if (!execute_statements
181 			    (result, packet, lease, client_state,
182 			     in_options, out_options, scope,
183 			     rc ? r->data.ie.tc : r->data.ie.fc,
184 			     on_star))
185 				return 0;
186 			break;
187 
188 		      case eval_statement:
189 			status = evaluate_expression
190 				(NULL, packet, lease, client_state, in_options,
191 				 out_options, scope, r->data.eval, MDL);
192 #if defined (DEBUG_EXPRESSIONS)
193 			log_debug ("exec: evaluate: %s",
194 				   (status ? "succeeded" : "failed"));
195 #else
196 			POST(status);
197 #endif
198 			break;
199 
200                       case execute_statement: {
201 #ifdef ENABLE_EXECUTE
202                         struct expression *expr;
203                         char **argv;
204                         int i, argc = r->data.execute.argc;
205                         pid_t p;
206 
207                         /* save room for the command and the NULL terminator */
208                         argv = dmalloc((argc + 2) * sizeof(*argv), MDL);
209                         if (!argv)
210                                 break;
211 
212                         argv[0] = dmalloc(strlen(r->data.execute.command) + 1,
213                                           MDL);
214                         if (argv[0]) {
215                                 strcpy(argv[0], r->data.execute.command);
216                         } else {
217                                 goto execute_out;
218                         }
219 
220                         log_debug("execute_statement argv[0] = %s", argv[0]);
221 
222                         for (i = 1, expr = r->data.execute.arglist; expr;
223                              expr = expr->data.arg.next, i++) {
224                                 memset (&ds, 0, sizeof(ds));
225                                 status = (evaluate_data_expression
226                                           (&ds, packet,
227                                            lease, client_state, in_options,
228                                            out_options, scope,
229                                            expr->data.arg.val, MDL));
230                                 if (status) {
231                                         argv[i] = dmalloc(ds.len + 1, MDL);
232                                         if (argv[i]) {
233                                                 memcpy(argv[i], ds.data,
234                                                        ds.len);
235                                                 argv[i][ds.len] = 0;
236                                                 log_debug("execute_statement argv[%d] = %s", i, argv[i]);
237                                         }
238                                         data_string_forget (&ds, MDL);
239                                         if (!argv[i]) {
240                                                 log_debug("execute_statement failed argv[%d]", i);
241                                                 goto execute_out;
242                                         }
243                                 } else {
244                                         log_debug("execute: bad arg %d", i);
245                                         goto execute_out;
246                                 }
247                         }
248                         argv[i] = NULL;
249 
250 	                if ((p = fork()) > 0) {
251 		        	int status;
252 		        	waitpid(p, &status, 0);
253 
254                         	if (status) {
255                                 	log_error("execute: %s exit status %d",
256                                           	   argv[0], status);
257                                 }
258 	                } else if (p == 0) {
259 		               execvp(argv[0], argv);
260 		               log_error("Unable to execute %s: %m", argv[0]);
261 		               _exit(127);
262                         } else {
263                                 log_error("execute: fork() failed");
264                         }
265 
266                       execute_out:
267                         for (i = 0; i <= argc; i++) {
268                                 if(argv[i])
269                                 	dfree(argv[i], MDL);
270                         }
271 
272                         dfree(argv, MDL);
273 #else /* !ENABLE_EXECUTE */
274 		        log_fatal("Impossible case at %s:%d (ENABLE_EXECUTE "
275 			          "is not defined).", MDL);
276 #endif /* ENABLE_EXECUTE */
277                         break;
278                       }
279 
280 		      case return_statement:
281 			status = evaluate_expression
282 				(result, packet,
283 				 lease, client_state, in_options,
284 				 out_options, scope, r -> data.retval, MDL);
285 #if defined (DEBUG_EXPRESSIONS)
286 			log_debug ("exec: return: %s",
287 				   (status ? "succeeded" : "failed"));
288 #else
289 			POST(status);
290 #endif
291 			break;
292 
293 		      case add_statement:
294 #if defined (DEBUG_EXPRESSIONS)
295 			log_debug ("exec: add %s", (r->data.add->name
296 					       ? r->data.add->name
297 					       : "<unnamed class>"));
298 #endif
299 			libdhcp_callbacks.classify (packet, r->data.add);
300 			break;
301 
302 		      case break_statement:
303 #if defined (DEBUG_EXPRESSIONS)
304 			log_debug ("exec: break");
305 #endif
306 			return 1;
307 
308 		      case supersede_option_statement:
309 		      case send_option_statement:
310 #if defined (DEBUG_EXPRESSIONS)
311 			log_debug ("exec: %s option %s.%s",
312 			      (r->op == supersede_option_statement
313 			       ? "supersede" : "send"),
314 			      r->data.option->option->universe->name,
315 			      r->data.option->option->name);
316 			goto option_statement;
317 #endif
318 		      case default_option_statement:
319 #if defined (DEBUG_EXPRESSIONS)
320 			log_debug ("exec: default option %s.%s",
321 			      r->data.option->option->universe->name,
322 			      r->data.option->option->name);
323 			goto option_statement;
324 #endif
325 		      case append_option_statement:
326 #if defined (DEBUG_EXPRESSIONS)
327 			log_debug ("exec: append option %s.%s",
328 			      r->data.option->option->universe->name,
329 			      r->data.option->option->name);
330 			goto option_statement;
331 #endif
332 		      case prepend_option_statement:
333 #if defined (DEBUG_EXPRESSIONS)
334 			log_debug ("exec: prepend option %s.%s",
335 			      r->data.option->option->universe->name,
336 			      r->data.option->option->name);
337 		      option_statement:
338 #endif
339 			set_option (r->data.option->option->universe,
340 				    out_options, r->data.option, r->op);
341 			break;
342 
343 		      case set_statement:
344 		      case define_statement:
345 			status = 1;
346 			if (!scope) {
347 				log_error("set %s: no scope",
348 					   r->data.set.name);
349 				break;
350 			}
351 			if (!*scope) {
352 			    if (!binding_scope_allocate(scope, MDL)) {
353 				log_error("set %s: can't allocate scope",
354 					  r->data.set.name);
355 				break;
356 			    }
357 			}
358 			binding = find_binding(*scope, r->data.set.name);
359 #if defined (DEBUG_EXPRESSIONS)
360 			log_debug("exec: set %s", r->data.set.name);
361 #else
362 			POST(status);
363 #endif
364 			if (binding == NULL) {
365 				binding = dmalloc(sizeof(*binding), MDL);
366 				if (binding != NULL) {
367 				    memset(binding, 0, sizeof(*binding));
368 				    binding->name =
369 					    dmalloc(strlen
370 						    (r->data.set.name) + 1,
371 						    MDL);
372 				    if (binding->name != NULL) {
373 					strcpy(binding->name, r->data.set.name);
374 					binding->next = (*scope)->bindings;
375 					(*scope)->bindings = binding;
376 				    } else {
377 					dfree(binding, MDL);
378 					binding = NULL;
379 				    }
380 				}
381 			}
382 			if (binding != NULL) {
383 				if (binding->value != NULL)
384 					binding_value_dereference
385 						(&binding->value, MDL);
386 				if (r->op == set_statement) {
387 					status = (evaluate_expression
388 						  (&binding->value, packet,
389 						   lease, client_state,
390 						   in_options, out_options,
391 						   scope, r->data.set.expr,
392 						   MDL));
393 				} else {
394 				    if (!(binding_value_allocate
395 					  (&binding->value, MDL))) {
396 					    dfree(binding, MDL);
397 					    binding = NULL;
398 				    }
399 				    if ((binding != NULL) &&
400 					(binding->value != NULL)) {
401 					    binding->value->type =
402 						    binding_function;
403 					    (fundef_reference
404 					     (&binding->value->value.fundef,
405 					      r->data.set.expr->data.func,
406 					      MDL));
407 				    }
408 				}
409 			}
410 #if defined (DEBUG_EXPRESSIONS)
411 			log_debug ("exec: set %s%s", r -> data.set.name,
412 				   (binding && status ? "" : " (failed)"));
413 #else
414 			POST(status);
415 #endif
416 			break;
417 
418 		      case unset_statement:
419 			if (!scope || !*scope)
420 				break;
421 			binding = find_binding (*scope, r->data.unset);
422 			if (binding) {
423 				if (binding->value)
424 					binding_value_dereference
425 						(&binding->value, MDL);
426 				status = 1;
427 			} else
428 				status = 0;
429 #if defined (DEBUG_EXPRESSIONS)
430 			log_debug ("exec: unset %s: %s", r->data.unset,
431 				   (status ? "found" : "not found"));
432 #else
433 			POST(status);
434 #endif
435 			break;
436 
437 		      case let_statement:
438 #if defined (DEBUG_EXPRESSIONS)
439 			log_debug("exec: let %s", r->data.let.name);
440 #endif
441 			status = 0;
442 			ns = NULL;
443 			binding_scope_allocate (&ns, MDL);
444 			e = r;
445 
446 		      next_let:
447 			if (ns) {
448 				binding = dmalloc(sizeof(*binding), MDL);
449 				if (!binding) {
450 				   blb:
451 				    binding_scope_dereference(&ns, MDL);
452 				} else {
453 				    memset(binding, 0, sizeof(*binding));
454 				    binding->name =
455 					    dmalloc(strlen
456 						    (e->data.let.name + 1),
457 						    MDL);
458 				    if (binding->name)
459 					strcpy(binding->name,
460 					       e->data.let.name);
461 				    else {
462 					dfree(binding, MDL);
463 					binding = NULL;
464 					goto blb;
465 				    }
466 				}
467 			} else
468 				binding = NULL;
469 
470 			if (ns && binding) {
471 				status = (evaluate_expression
472 					  (&binding->value, packet, lease,
473 					   client_state,
474 					   in_options, out_options,
475 					   scope, e->data.set.expr, MDL));
476 				binding->next = ns->bindings;
477 				ns->bindings = binding;
478 			}
479 
480 #if defined (DEBUG_EXPRESSIONS)
481 			log_debug("exec: let %s%s", e->data.let.name,
482 				  (binding && status ? "" : "failed"));
483 #else
484 			POST(status);
485 #endif
486 			if (!e->data.let.statements) {
487 			} else if (e->data.let.statements->op ==
488 				   let_statement) {
489 				e = e->data.let.statements;
490 				goto next_let;
491 			} else if (ns) {
492 				if (scope && *scope)
493 				    	binding_scope_reference(&ns->outer,
494 								*scope, MDL);
495 				execute_statements
496 				      (result, packet, lease, client_state,
497 				       in_options, out_options,
498 				       &ns, e->data.let.statements, on_star);
499 			}
500 			if (ns)
501 				binding_scope_dereference(&ns, MDL);
502 			break;
503 
504 		      case log_statement:
505 			memset (&ds, 0, sizeof ds);
506 			status = (evaluate_data_expression
507 				  (&ds, packet,
508 				   lease, client_state, in_options,
509 				   out_options, scope, r->data.log.expr, MDL));
510 
511 #if defined (DEBUG_EXPRESSIONS)
512 			log_debug ("exec: log");
513 #endif
514 
515 			if (status) {
516 				switch (r->data.log.priority) {
517 				case log_priority_fatal:
518 					log_fatal ("%.*s", (int)ds.len,
519 						ds.data);
520 					break;
521 				case log_priority_error:
522 					log_error ("%.*s", (int)ds.len,
523 						ds.data);
524 					break;
525 				case log_priority_debug:
526 					log_debug ("%.*s", (int)ds.len,
527 						ds.data);
528 					break;
529 				case log_priority_info:
530 					log_info ("%.*s", (int)ds.len,
531 						ds.data);
532 					break;
533 				}
534 				data_string_forget (&ds, MDL);
535 			}
536 
537 			break;
538 
539 		      case vendor_opt_statement:
540 		        /* If possible parse any options in a vendor option
541 			 * encapsulation, this may add options to the in_options
542 			 * option state */
543 			parse_vendor_option(packet, lease, client_state,
544 					    in_options, out_options, scope);
545 			break;
546 
547 		      default:
548 			log_error ("bogus statement type %d", r -> op);
549 			break;
550 		}
551 		executable_statement_dereference (&r, MDL);
552 		if (next) {
553 			executable_statement_reference (&r, next, MDL);
554 			executable_statement_dereference (&next, MDL);
555 		}
556 	}
557 
558 	return 1;
559 }
560 
561 /* Execute all the statements in a particular scope, and all statements in
562    scopes outer from that scope, but if a particular limiting scope is
563    reached, do not execute statements in that scope or in scopes outer
564    from it.   More specific scopes need to take precedence over less
565    specific scopes, so we recursively traverse the scope list, executing
566    the most outer scope first. */
567 
568 void execute_statements_in_scope (result, packet,
569 				  lease, client_state, in_options, out_options,
570 				  scope, group, limiting_group, on_star)
571 	struct binding_value **result;
572 	struct packet *packet;
573 	struct lease *lease;
574 	struct client_state *client_state;
575 	struct option_state *in_options;
576 	struct option_state *out_options;
577 	struct binding_scope **scope;
578 	struct group *group;
579 	struct group *limiting_group;
580 	struct on_star *on_star;
581 {
582 	struct group *limit;
583 
584 	/* If we've recursed as far as we can, return. */
585 	if (!group)
586 		return;
587 
588 	/* As soon as we get to a scope that is outer than the limiting
589 	   scope, we are done.   This is so that if somebody does something
590 	   like this, it does the expected thing:
591 
592 	        domain-name "example.com";
593 		shared-network FOO {
594 			host bar {
595 				domain-name "othello.example.com";
596 				fixed-address 10.20.30.40;
597 			}
598 			subnet 10.20.30.0 netmask 255.255.255.0 {
599 				domain-name "manhattan.example.com";
600 			}
601 		}
602 
603 	   The problem with the above arrangement is that the host's
604 	   group nesting will be host -> shared-network -> top-level,
605 	   and the limiting scope when we evaluate the host's scope
606 	   will be the subnet -> shared-network -> top-level, so we need
607 	   to know when we evaluate the host's scope to stop before we
608 	   evaluate the shared-networks scope, because it's outer than
609 	   the limiting scope, which means we've already evaluated it. */
610 
611 	for (limit = limiting_group; limit; limit = limit -> next) {
612 		if (group == limit)
613 			return;
614 	}
615 
616 	if (group -> next)
617 		execute_statements_in_scope (result, packet,
618 					     lease, client_state,
619 					     in_options, out_options, scope,
620 					     group->next, limiting_group,
621 					     on_star);
622 	execute_statements (result, packet, lease, client_state, in_options,
623 			    out_options, scope, group->statements, on_star);
624 }
625 
626 /* Dereference or free any subexpressions of a statement being freed. */
627 
628 int executable_statement_dereference (ptr, file, line)
629 	struct executable_statement **ptr;
630 	const char *file;
631 	int line;
632 {
633 	if (!ptr || !*ptr) {
634 		log_error ("%s(%d): null pointer", file, line);
635 #if defined (POINTER_DEBUG)
636 		abort ();
637 #else
638 		return 0;
639 #endif
640 	}
641 
642 	(*ptr) -> refcnt--;
643 	rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC);
644 	if ((*ptr) -> refcnt > 0) {
645 		*ptr = (struct executable_statement *)0;
646 		return 1;
647 	}
648 
649 	if ((*ptr) -> refcnt < 0) {
650 		log_error ("%s(%d): negative refcnt!", file, line);
651 #if defined (DEBUG_RC_HISTORY)
652 		dump_rc_history (*ptr);
653 #endif
654 #if defined (POINTER_DEBUG)
655 		abort ();
656 #else
657 		return 0;
658 #endif
659 	}
660 
661 	if ((*ptr) -> next)
662 		executable_statement_dereference (&(*ptr) -> next, file, line);
663 
664 	switch ((*ptr) -> op) {
665 	      case statements_statement:
666 		if ((*ptr) -> data.statements)
667 			executable_statement_dereference
668 				(&(*ptr) -> data.statements, file, line);
669 		break;
670 
671 	      case on_statement:
672 		if ((*ptr) -> data.on.statements)
673 			executable_statement_dereference
674 				(&(*ptr) -> data.on.statements, file, line);
675 		break;
676 
677 	      case switch_statement:
678 		if ((*ptr) -> data.s_switch.statements)
679 			executable_statement_dereference
680 				(&(*ptr) -> data.on.statements, file, line);
681 		if ((*ptr) -> data.s_switch.expr)
682 			expression_dereference (&(*ptr) -> data.s_switch.expr,
683 						file, line);
684 		break;
685 
686 	      case case_statement:
687 		if ((*ptr) -> data.s_switch.expr)
688 			expression_dereference (&(*ptr) -> data.c_case,
689 						file, line);
690 		break;
691 
692 	      case if_statement:
693 		if ((*ptr) -> data.ie.expr)
694 			expression_dereference (&(*ptr) -> data.ie.expr,
695 						file, line);
696 		if ((*ptr) -> data.ie.tc)
697 			executable_statement_dereference
698 				(&(*ptr) -> data.ie.tc, file, line);
699 		if ((*ptr) -> data.ie.fc)
700 			executable_statement_dereference
701 				(&(*ptr) -> data.ie.fc, file, line);
702 		break;
703 
704 	      case eval_statement:
705 		if ((*ptr) -> data.eval)
706 			expression_dereference (&(*ptr) -> data.eval,
707 						file, line);
708 		break;
709 
710 	      case return_statement:
711 		if ((*ptr) -> data.eval)
712 			expression_dereference (&(*ptr) -> data.eval,
713 						file, line);
714 		break;
715 
716 	      case set_statement:
717 		if ((*ptr)->data.set.name)
718 			dfree ((*ptr)->data.set.name, file, line);
719 		if ((*ptr)->data.set.expr)
720 			expression_dereference (&(*ptr) -> data.set.expr,
721 						file, line);
722 		break;
723 
724 	      case unset_statement:
725 		if ((*ptr)->data.unset)
726 			dfree ((*ptr)->data.unset, file, line);
727 		break;
728 
729 	      case execute_statement:
730 		if ((*ptr)->data.execute.command)
731 			dfree ((*ptr)->data.execute.command, file, line);
732 		if ((*ptr)->data.execute.arglist)
733 			expression_dereference (&(*ptr) -> data.execute.arglist,
734 						file, line);
735 		break;
736 
737 	      case supersede_option_statement:
738 	      case send_option_statement:
739 	      case default_option_statement:
740 	      case append_option_statement:
741 	      case prepend_option_statement:
742 		if ((*ptr) -> data.option)
743 			option_cache_dereference (&(*ptr) -> data.option,
744 						  file, line);
745 		break;
746 
747 	      default:
748 		/* Nothing to do. */
749 		break;
750 	}
751 
752 	dfree ((*ptr), file, line);
753 	*ptr = (struct executable_statement *)0;
754 	return 1;
755 }
756 
757 void write_statements (file, statements, indent)
758 	FILE *file;
759 	struct executable_statement *statements;
760 	int indent;
761 {
762 #if defined ENABLE_EXECUTE
763 	struct expression *expr;
764 #endif
765 	struct executable_statement *r, *x;
766 	const char *s, *t, *dot;
767 	int col;
768 
769 	if (!statements)
770 		return;
771 
772 	for (r = statements; r; r = r -> next) {
773 		switch (r -> op) {
774 		      case statements_statement:
775 			write_statements (file, r -> data.statements, indent);
776 			break;
777 
778 		      case on_statement:
779 			indent_spaces (file, indent);
780 			fprintf (file, "on ");
781 			s = "";
782 			if (r -> data.on.evtypes & ON_EXPIRY) {
783 				fprintf (file, "%sexpiry", s);
784 				s = " or ";
785 			}
786 			if (r -> data.on.evtypes & ON_COMMIT) {
787 				fprintf (file, "%scommit", s);
788 				s = " or ";
789 			}
790 			if (r -> data.on.evtypes & ON_RELEASE) {
791 				fprintf (file, "%srelease", s);
792 				/* s = " or "; */
793 			}
794 			if (r -> data.on.statements) {
795 				fprintf (file, " {");
796 				write_statements (file,
797 						  r -> data.on.statements,
798 						  indent + 2);
799 				indent_spaces (file, indent);
800 				fprintf (file, "}");
801 			} else {
802 				fprintf (file, ";");
803 			}
804 			break;
805 
806 		      case switch_statement:
807 			indent_spaces (file, indent);
808 			fprintf (file, "switch (");
809 			col = write_expression (file,
810 						r -> data.s_switch.expr,
811 						indent + 7, indent + 7, 1);
812 			col = token_print_indent (file, col, indent + 7,
813 						  "", "", ")");
814 			token_print_indent (file,
815 					    col, indent, " ", "", "{");
816 			write_statements (file, r -> data.s_switch.statements,
817 					  indent + 2);
818 			indent_spaces (file, indent);
819 			fprintf (file, "}");
820 			break;
821 
822 		      case case_statement:
823 			indent_spaces (file, indent - 1);
824 			fprintf (file, "case ");
825 			col = write_expression (file,
826 						r -> data.s_switch.expr,
827 						indent + 5, indent + 5, 1);
828 			token_print_indent (file, col, indent + 5,
829 					    "", "", ":");
830 			break;
831 
832 		      case default_statement:
833 			indent_spaces (file, indent - 1);
834 			fprintf (file, "default: ");
835 			break;
836 
837 		      case if_statement:
838 			indent_spaces (file, indent);
839 			fprintf (file, "if ");
840 			x = r;
841 			col = write_expression (file,
842 						x -> data.ie.expr,
843 						indent + 3, indent + 3, 1);
844 		      else_if:
845 			token_print_indent (file, col, indent, " ", "", "{");
846 			write_statements (file, x -> data.ie.tc, indent + 2);
847 			if (x -> data.ie.fc &&
848 			    x -> data.ie.fc -> op == if_statement &&
849 			    !x -> data.ie.fc -> next) {
850 				indent_spaces (file, indent);
851 				fprintf (file, "} elsif ");
852 				x = x -> data.ie.fc;
853 				col = write_expression (file,
854 							x -> data.ie.expr,
855 							indent + 6,
856 							indent + 6, 1);
857 				goto else_if;
858 			}
859 			if (x -> data.ie.fc) {
860 				indent_spaces (file, indent);
861 				fprintf (file, "} else {");
862 				write_statements (file, x -> data.ie.fc,
863 						  indent + 2);
864 			}
865 			indent_spaces (file, indent);
866 			fprintf (file, "}");
867 			break;
868 
869 		      case eval_statement:
870 			indent_spaces (file, indent);
871 			fprintf (file, "eval ");
872 			(void) write_expression (file, r -> data.eval,
873 						indent + 5, indent + 5, 1);
874 			fprintf (file, ";");
875 			break;
876 
877 		      case return_statement:
878 			indent_spaces (file, indent);
879 			fprintf (file, "return;");
880 			break;
881 
882 		      case add_statement:
883 			indent_spaces (file, indent);
884 			fprintf (file, "add \"%s\"", r -> data.add -> name);
885 			break;
886 
887 		      case break_statement:
888 			indent_spaces (file, indent);
889 			fprintf (file, "break;");
890 			break;
891 
892 		      case supersede_option_statement:
893 		      case send_option_statement:
894 			s = "supersede";
895 			goto option_statement;
896 
897 		      case default_option_statement:
898 			s = "default";
899 			goto option_statement;
900 
901 		      case append_option_statement:
902 			s = "append";
903 			goto option_statement;
904 
905 		      case prepend_option_statement:
906 			s = "prepend";
907 		      option_statement:
908 			/* Note: the reason we don't try to pretty print
909 			   the option here is that the format of the option
910 			   may change in dhcpd.conf, and then when this
911 			   statement was read back, it would cause a syntax
912 			   error. */
913 			if (r -> data.option -> option -> universe ==
914 			    &dhcp_universe) {
915 				t = "";
916 				dot = "";
917 			} else {
918 				t = (r -> data.option -> option ->
919 				     universe -> name);
920 				dot = ".";
921 			}
922 			indent_spaces (file, indent);
923 			fprintf (file, "%s %s%s%s = ", s, t, dot,
924 				 r -> data.option -> option -> name);
925 			col = (indent + strlen (s) + strlen (t) +
926 			       strlen (dot) + strlen (r -> data.option ->
927 						      option -> name) + 4);
928 			if (r -> data.option -> expression)
929 				write_expression
930 					(file,
931 					 r -> data.option -> expression,
932 					 col, indent + 8, 1);
933 			else
934 				token_indent_data_string
935 					(file, col, indent + 8, "", "",
936 					 &r -> data.option -> data);
937 
938 			fprintf (file, ";"); /* XXX */
939 			break;
940 
941 		      case set_statement:
942 			indent_spaces (file, indent);
943 			fprintf (file, "set ");
944 			col = token_print_indent (file, indent + 4, indent + 4,
945 						  "", "", r -> data.set.name);
946 			(void) token_print_indent (file, col, indent + 4,
947 						  " ", " ", "=");
948 			col = write_expression (file, r -> data.set.expr,
949 						indent + 3, indent + 3, 0);
950 			(void) token_print_indent (file, col, indent + 4,
951 						  " ", "", ";");
952 			break;
953 
954 		      case unset_statement:
955 			indent_spaces (file, indent);
956 			fprintf (file, "unset ");
957 			col = token_print_indent (file, indent + 6, indent + 6,
958 						  "", "", r -> data.set.name);
959 			(void) token_print_indent (file, col, indent + 6,
960 						  " ", "", ";");
961 			break;
962 
963 		      case log_statement:
964 			indent_spaces (file, indent);
965 			fprintf (file, "log ");
966 			col = token_print_indent (file, indent + 4, indent + 4,
967 						  "", "", "(");
968 			switch (r -> data.log.priority) {
969 			case log_priority_fatal:
970 				(void) token_print_indent
971 					(file, col, indent + 4, "",
972 					 " ", "fatal,");
973 				break;
974 			case log_priority_error:
975 				(void) token_print_indent
976 					(file, col, indent + 4, "",
977 					 " ", "error,");
978 				break;
979 			case log_priority_debug:
980 				(void) token_print_indent
981 					(file, col, indent + 4, "",
982 					 " ", "debug,");
983 				break;
984 			case log_priority_info:
985 				(void) token_print_indent
986 					(file, col, indent + 4, "",
987 					 " ", "info,");
988 				break;
989 			}
990 			col = write_expression (file, r -> data.log.expr,
991 						indent + 4, indent + 4, 0);
992 			(void) token_print_indent (file, col, indent + 4,
993 						  "", "", ");");
994 
995 			break;
996 
997                       case execute_statement:
998 
999 #ifdef ENABLE_EXECUTE
1000 			indent_spaces(file, indent);
1001 			col = token_print_indent(file, indent + 4, indent + 4,
1002 						 "", "", "execute");
1003 			col = token_print_indent(file, col, indent + 4, " ", "",
1004 						 "(");
1005 			col = token_print_indent_concat(file, col, indent + 4,
1006 							"", "",  "\"",
1007 							r->data.execute.command,
1008 							"\"", (char *)0);
1009 			for (expr = r->data.execute.arglist; expr; expr = expr->data.arg.next) {
1010 				col = token_print_indent(file, col, indent + 4,
1011 							 "", " ", ",");
1012 				col = write_expression(file, expr->data.arg.val,
1013 						       col, indent + 4, 0);
1014 			}
1015 			(void) token_print_indent(file, col, indent + 4,
1016 						  "", "", ");");
1017 #else /* !ENABLE_EXECUTE */
1018 		        log_fatal("Impossible case at %s:%d (ENABLE_EXECUTE "
1019                                   "is not defined).", MDL);
1020 #endif /* ENABLE_EXECUTE */
1021                         break;
1022 
1023 		      case vendor_opt_statement:
1024 			indent_spaces (file, indent);
1025 			fprintf (file, "parse-vendor-option;");
1026 			break;
1027 
1028 		      default:
1029 			log_fatal ("bogus statement type %d\n", r -> op);
1030 		}
1031 	}
1032 }
1033 
1034 /* Find a case statement in the sequence of executable statements that
1035    matches the expression, and if found, return the following statement.
1036    If no case statement matches, try to find a default statement and
1037    return that (the default statement can precede all the case statements).
1038    Otherwise, return the null statement. */
1039 
1040 int find_matching_case (struct executable_statement **ep,
1041 			struct packet *packet, struct lease *lease,
1042 			struct client_state *client_state,
1043 			struct option_state *in_options,
1044 			struct option_state *out_options,
1045 			struct binding_scope **scope,
1046 			struct expression *expr,
1047 			struct executable_statement *stmt)
1048 {
1049 	int status, sub;
1050 	struct executable_statement *s;
1051 
1052 	if (is_data_expression (expr)) {
1053 		struct data_string cd, ds;
1054 		memset (&ds, 0, sizeof ds);
1055 		memset (&cd, 0, sizeof cd);
1056 
1057 		status = (evaluate_data_expression (&ds, packet, lease,
1058 						    client_state, in_options,
1059 						    out_options, scope, expr,
1060 						    MDL));
1061 		if (status) {
1062 		    for (s = stmt; s; s = s -> next) {
1063 			if (s -> op == case_statement) {
1064 				sub = (evaluate_data_expression
1065 				       (&cd, packet, lease, client_state,
1066 					in_options, out_options,
1067 					scope, s->data.c_case, MDL));
1068 				if (sub && cd.len == ds.len &&
1069 				    !memcmp (cd.data, ds.data, cd.len))
1070 				{
1071 					data_string_forget (&cd, MDL);
1072 					data_string_forget (&ds, MDL);
1073 					executable_statement_reference
1074 						(ep, s->next, MDL);
1075 					return 1;
1076 				}
1077 				data_string_forget (&cd, MDL);
1078 			}
1079 		    }
1080 		    data_string_forget (&ds, MDL);
1081 		}
1082 	} else {
1083 		unsigned long n, c;
1084 		status = evaluate_numeric_expression (&n, packet, lease,
1085 						      client_state,
1086 						      in_options, out_options,
1087 						      scope, expr);
1088 
1089 		if (status) {
1090 		    for (s = stmt; s; s = s->next) {
1091 			if (s -> op == case_statement) {
1092 				sub = (evaluate_numeric_expression
1093 				       (&c, packet, lease, client_state,
1094 					in_options, out_options,
1095 					scope, s->data.c_case));
1096 				if (sub && n == c) {
1097 					executable_statement_reference
1098 						(ep, s->next, MDL);
1099 					return 1;
1100 				}
1101 			}
1102 		    }
1103 		}
1104 	}
1105 
1106 	/* If we didn't find a matching case statement, look for a default
1107 	   statement and return the statement following it. */
1108 	for (s = stmt; s; s = s->next)
1109 		if (s->op == default_statement)
1110 			break;
1111 	if (s) {
1112 		executable_statement_reference (ep, s->next, MDL);
1113 		return 1;
1114 	}
1115 	return 0;
1116 }
1117 
1118 int executable_statement_foreach (struct executable_statement *stmt,
1119 				  int (*callback) (struct
1120 						   executable_statement *,
1121 						   void *, int),
1122 				  void *vp, int condp)
1123 {
1124 	struct executable_statement *foo;
1125 	int ok = 0;
1126 
1127 	for (foo = stmt; foo; foo = foo->next) {
1128 	    if ((*callback) (foo, vp, condp) != 0)
1129 		ok = 1;
1130 	    switch (foo->op) {
1131 	      case null_statement:
1132 		break;
1133 	      case if_statement:
1134 		if (executable_statement_foreach (foo->data.ie.tc,
1135 						  callback, vp, 1))
1136 			ok = 1;
1137 		if (executable_statement_foreach (foo->data.ie.fc,
1138 						  callback, vp, 1))
1139 			ok = 1;
1140 		break;
1141 	      case add_statement:
1142 		break;
1143 	      case eval_statement:
1144 		break;
1145 	      case break_statement:
1146 		break;
1147 	      case default_option_statement:
1148 		break;
1149 	      case supersede_option_statement:
1150 		break;
1151 	      case append_option_statement:
1152 		break;
1153 	      case prepend_option_statement:
1154 		break;
1155 	      case send_option_statement:
1156 		break;
1157 	      case statements_statement:
1158 		if ((executable_statement_foreach
1159 		     (foo->data.statements, callback, vp, condp)))
1160 			ok = 1;
1161 		break;
1162 	      case on_statement:
1163 		if ((executable_statement_foreach
1164 		     (foo->data.on.statements, callback, vp, 1)))
1165 			ok = 1;
1166 		break;
1167 	      case switch_statement:
1168 		if ((executable_statement_foreach
1169 		     (foo->data.s_switch.statements, callback, vp, 1)))
1170 			ok = 1;
1171 		break;
1172 	      case case_statement:
1173 		break;
1174 	      case default_statement:
1175 		break;
1176 	      case set_statement:
1177 		break;
1178 	      case unset_statement:
1179 		break;
1180 	      case let_statement:
1181 		if ((executable_statement_foreach
1182 		     (foo->data.let.statements, callback, vp, 0)))
1183 			ok = 1;
1184 		break;
1185 	      case define_statement:
1186 		break;
1187 	      case log_statement:
1188 	      case return_statement:
1189 	      case execute_statement:
1190 	      case vendor_opt_statement:
1191 		break;
1192 	    }
1193 	}
1194 	return ok;
1195 }
1196