[BACK]Return to execute.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / external / mpl / dhcp / dist / common

Annotation of src/external/mpl/dhcp/dist/common/execute.c, Revision 1.1.1.3

1.1       christos    1: /*     $NetBSD$        */
                      2:
                      3: /* execute.c
                      4:
                      5:    Support for executable statements. */
                      6:
                      7: /*
1.1.1.3 ! christos    8:  * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
1.1       christos    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.
1.1.1.3 ! christos   24:  *   PO Box 360
        !            25:  *   Newmarket, NH 03857 USA
1.1       christos   26:  *   <info@isc.org>
                     27:  *   https://www.isc.org/
                     28:  *
                     29:  */
                     30:
                     31: #include <sys/cdefs.h>
                     32: __RCSID("$NetBSD$");
                     33:
                     34: #include "dhcpd.h"
                     35: #include <isc/util.h>
                     36: #include <omapip/omapip_p.h>
                     37: #include <sys/types.h>
                     38: #include <sys/wait.h>
                     39:
                     40: int execute_statements (result, packet, lease, client_state,
                     41:                        in_options, out_options, scope, statements,
                     42:                        on_star)
                     43:        struct binding_value **result;
                     44:        struct packet *packet;
                     45:        struct lease *lease;
                     46:        struct client_state *client_state;
                     47:        struct option_state *in_options;
                     48:        struct option_state *out_options;
                     49:        struct binding_scope **scope;
                     50:        struct executable_statement *statements;
                     51:        struct on_star *on_star;
                     52: {
                     53:        struct executable_statement *r, *e, *next;
                     54:        int rc;
                     55:        int status;
                     56:        struct binding *binding;
                     57:        struct data_string ds;
                     58:        struct binding_scope *ns;
                     59:
                     60:        if (!statements)
                     61:                return 1;
                     62:
                     63:        r = NULL;
                     64:        next = NULL;
                     65:        e = NULL;
                     66:        executable_statement_reference (&r, statements, MDL);
                     67:        while (r && !(result && *result)) {
                     68:                if (r->next)
                     69:                        executable_statement_reference (&next, r->next, MDL);
                     70:                switch (r->op) {
                     71:                      case statements_statement:
                     72: #if defined (DEBUG_EXPRESSIONS)
                     73:                        log_debug ("exec: statements");
                     74: #endif
                     75:                        status = execute_statements (result, packet, lease,
                     76:                                                     client_state, in_options,
                     77:                                                     out_options, scope,
                     78:                                                     r->data.statements,
                     79:                                                     on_star);
                     80: #if defined (DEBUG_EXPRESSIONS)
                     81:                        log_debug ("exec: statements returns %d", status);
                     82: #endif
1.1.1.2   christos   83:                        if (!status) {
                     84:                                executable_statement_dereference (&r, MDL);
1.1       christos   85:                                return 0;
1.1.1.2   christos   86:                        }
1.1       christos   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);
1.1.1.2   christos  157:                                        executable_statement_dereference
                    158:                                                (&r, MDL);
1.1       christos  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));
1.1.1.3 ! christos  175:
1.1       christos  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,
1.1.1.2   christos  188:                             on_star)) {
                    189:                                executable_statement_dereference (&r, MDL);
1.1       christos  190:                                return 0;
1.1.1.2   christos  191:                        }
1.1       christos  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]);
1.1.1.3 ! christos  227:
1.1       christos  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:                        classify (packet, r->data.add);
                    306:                        break;
                    307:
                    308:                      case break_statement:
                    309: #if defined (DEBUG_EXPRESSIONS)
                    310:                        log_debug ("exec: break");
                    311: #endif
1.1.1.2   christos  312:                        executable_statement_dereference (&r, MDL);
1.1       christos  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));
1.1.1.3 ! christos  517:
1.1       christos  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:
                    575: void 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:
                    635: int 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:
                    764: void 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);
1.1.1.3 ! christos  944:
1.1       christos  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;
1.1.1.3 ! christos  960:
1.1       christos  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;
1.1.1.3 ! christos 1029:
1.1       christos 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:
                   1047: int 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:
                   1125: int 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: }

CVSweb <webmaster@jp.NetBSD.org>