Annotation of embedaddon/dhcp/common/execute.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>