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