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