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