]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
New malloc debug scheme. Support variable scoping.
authorTed Lemon <source@isc.org>
Tue, 25 Jan 2000 01:36:29 +0000 (01:36 +0000)
committerTed Lemon <source@isc.org>
Tue, 25 Jan 2000 01:36:29 +0000 (01:36 +0000)
server/bootp.c
server/class.c
server/dhcp.c

index e6dce33429f9340e83854d7b21d1716a7302fa7c..8d8da7803c1670e839ea435e4cb8e648ff53448b 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: bootp.c,v 1.58 2000/01/05 18:12:09 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: bootp.c,v 1.59 2000/01/25 01:32:41 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -115,44 +115,47 @@ void bootp (packet)
 
        /* Run the executable statements to compute the client and server
           options. */
-       option_state_allocate (&options, "bootrequest");
+       option_state_allocate (&options, MDL);
        
        /* Execute the subnet statements. */
        execute_statements_in_scope (packet, lease, packet -> options, options,
-                                    lease -> subnet -> group,
+                                    &lease -> scope, lease -> subnet -> group,
                                     (struct group *)0);
        
        /* Execute statements from class scopes. */
        for (i = packet -> class_count; i > 0; i--) {
                execute_statements_in_scope
                        (packet, lease, packet -> options, options,
-                        packet -> classes [i - 1] -> group,
+                        &lease -> scope, packet -> classes [i - 1] -> group,
                         lease -> subnet -> group);
        }
 
        /* Execute the host statements. */
        execute_statements_in_scope (packet, lease, packet -> options, options,
+                                    &lease -> scope,
                                     hp -> group, subnet -> group);
        
        /* Drop the request if it's not allowed for this client. */
        if ((oc = lookup_option (&server_universe, options, SV_ALLOW_BOOTP)) &&
            !evaluate_boolean_option_cache (&ignorep, packet, lease,
-                                           packet -> options, options, oc)) {
+                                           packet -> options, options,
+                                           &lease -> scope, oc, MDL)) {
                if (!ignorep)
                        log_info ("%s: bootp disallowed", msgbuf);
-               option_state_dereference (&options, "bootrequest");
-               static_lease_dereference (lease, "bootrequest");
+               option_state_dereference (&options, MDL);
+               static_lease_dereference (lease, MDL);
                return;
        } 
 
        if ((oc = lookup_option (&server_universe,
                                 options, SV_ALLOW_BOOTING)) &&
            !evaluate_boolean_option_cache (&ignorep, packet, lease,
-                                           packet -> options, options, oc)) {
+                                           packet -> options, options,
+                                           &lease -> scope, oc, MDL)) {
                if (!ignorep)
                        log_info ("%s: booting disallowed", msgbuf);
-               option_state_dereference (&options, "bootrequest");
-               static_lease_dereference (lease, "bootrequest");
+               option_state_dereference (&options, MDL);
+               static_lease_dereference (lease, MDL);
                return;
        }
 
@@ -166,8 +169,9 @@ void bootp (packet)
        if (!packet -> options_valid &&
            !(evaluate_boolean_option_cache
              (&ignorep, packet, lease, packet -> options, options,
+              &lease -> scope,
               lookup_option (&server_universe, options,
-                             SV_ALWAYS_REPLY_RFC1048)))) {
+                             SV_ALWAYS_REPLY_RFC1048), MDL))) {
                memcpy (outgoing.raw -> options,
                        packet -> raw -> options, DHCP_OPTION_LEN);
                outgoing.packet_length = BOOTP_MIN_LEN;
@@ -179,7 +183,7 @@ void bootp (packet)
                oc = (struct option_cache *)0;
                i = DHO_SUBNET_MASK;
                if (!lookup_option (&dhcp_universe, options, i)) {
-                       if (option_cache_allocate (&oc, "ack_lease")) {
+                       if (option_cache_allocate (&oc, MDL)) {
                                if (make_const_data
                                    (&oc -> expression,
                                     lease -> subnet -> netmask.iabuf,
@@ -189,7 +193,7 @@ void bootp (packet)
                                        save_option (&dhcp_universe,
                                                     options, oc);
                                }
-                               option_cache_dereference (&oc, "ack_lease");
+                               option_cache_dereference (&oc, MDL);
                        }
                }
 
@@ -200,6 +204,7 @@ void bootp (packet)
                outgoing.packet_length =
                        cons_options (packet, outgoing.raw, lease, 0,
                                      packet -> options, options,
+                                     &lease -> scope,
                                      0, 0, 1, (struct data_string *)0);
                if (outgoing.packet_length < BOOTP_MIN_LEN)
                        outgoing.packet_length = BOOTP_MIN_LEN;
@@ -222,7 +227,8 @@ void bootp (packet)
        if ((oc = lookup_option (&server_universe,
                                options, SV_ALWAYS_BROADCAST)) &&
            evaluate_boolean_option_cache (&ignorep, packet, lease,
-                                          packet -> options, options, oc))
+                                          packet -> options, options,
+                                          &lease -> scope, oc, MDL))
                raw.flags |= htons (BOOTP_BROADCAST);
 
        /* Figure out the address of the next server. */
@@ -230,11 +236,12 @@ void bootp (packet)
        oc = lookup_option (&server_universe, options, SV_NEXT_SERVER);
        if (oc &&
            evaluate_option_cache (&d1, packet, lease,
-                                  packet -> options, options, oc)) {
+                                  packet -> options, options,
+                                  &lease -> scope, oc, MDL)) {
                /* If there was more than one answer, take the first. */
                if (d1.len >= 4 && d1.data)
                        memcpy (&raw.siaddr, d1.data, 4);
-               data_string_forget (&d1, "bootrequest");
+               data_string_forget (&d1, MDL);
        } else {
                if (lease -> subnet -> shared_network -> interface)
                        raw.siaddr = (lease -> subnet -> shared_network ->
@@ -249,13 +256,14 @@ void bootp (packet)
        oc = lookup_option (&server_universe, options, SV_FILENAME);
        if (oc &&
            evaluate_option_cache (&d1, packet, lease,
-                                  packet -> options, options, oc)) {
+                                  packet -> options, options,
+                                  &lease -> scope, oc, MDL)) {
                memcpy (raw.file, d1.data,
                        d1.len > sizeof raw.file ? sizeof raw.file : d1.len);
                if (sizeof raw.file > d1.len)
                        memset (&raw.file [d1.len],
                                0, (sizeof raw.file) - d1.len);
-               data_string_forget (&d1, "bootrequest");
+               data_string_forget (&d1, MDL);
        } else
                memcpy (raw.file, packet -> raw -> file, sizeof raw.file);
 
@@ -263,22 +271,23 @@ void bootp (packet)
        oc = lookup_option (&server_universe, options, SV_SERVER_NAME);
        if (oc &&
            evaluate_option_cache (&d1, packet, lease,
-                                  packet -> options, options, oc)) {
+                                  packet -> options, options,
+                                  &lease -> scope, oc, MDL)) {
                memcpy (raw.sname, d1.data,
                        d1.len > sizeof raw.sname ? sizeof raw.sname : d1.len);
                if (sizeof raw.sname > d1.len)
                        memset (&raw.sname [d1.len],
                                0, (sizeof raw.sname) - d1.len);
-               data_string_forget (&d1, "bootrequest");
+               data_string_forget (&d1, MDL);
        }
 
        /* Execute the commit statements, if there are any. */
        execute_statements (packet, lease, packet -> options,
-                           options, lease -> on_commit);
+                           options, &lease -> scope, lease -> on_commit);
 
        /* We're done with the option state. */
-       option_state_dereference (&options, "bootrequest");
-       static_lease_dereference (lease, "bootrequest");
+       option_state_dereference (&options, MDL);
+       static_lease_dereference (lease, MDL);
 
        /* Set up the hardware destination address... */
        hto.hbuf [0] = packet -> raw -> htype;
index 6e231402aa571eff04a06bc30b9d5d09a10da13a..46c6bfdc2a34e92d51cd98e6c68d0641053cd9d1 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: class.c,v 1.15 1999/10/21 03:09:13 mellon Exp $ Copyright (c) 1998 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: class.c,v 1.16 2000/01/25 01:36:29 mellon Exp $ Copyright (c) 1998 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -46,14 +46,12 @@ void classification_setup ()
 
        /* eval ... */
        rules = (struct executable_statement *)0;
-       if (!executable_statement_allocate (&rules,
-                                           "default collection check rule"))
+       if (!executable_statement_allocate (&rules, MDL))
                log_fatal ("Can't allocate check of default collection");
        rules -> op = eval_statement;
 
        /* check-collection "default" */
-       if (!expression_allocate (&rules -> data.eval,
-                                 "default check expression"))
+       if (!expression_allocate (&rules -> data.eval, MDL))
                log_fatal ("Can't allocate default check expression");
        rules -> data.eval -> op = expr_check;
        rules -> data.eval -> data.check = &default_collection;
@@ -65,7 +63,7 @@ void classify_client (packet)
        struct packet *packet;
 {
        execute_statements (packet, (struct lease *)0, packet -> options,
-                           (struct option_state *)0,
+                           (struct option_state *)0, &global_scope,
                            default_classification_rules);
 }
 
@@ -91,7 +89,7 @@ int check_collection (packet, lease, collection)
                        status = (evaluate_data_expression
                                  (&data, packet, lease,
                                   packet -> options, (struct option_state *)0,
-                                  class -> submatch));
+                                  &lease -> scope, class -> submatch));
                        if (status) {
                                if ((nc = ((struct class *)
                                           hash_lookup (class -> hash,
@@ -102,21 +100,21 @@ int check_collection (packet, lease, collection)
                                              print_hex_1 (data.len,
                                                           data.data, 60));
 #endif
-                                       data_string_forget
-                                               (&data, "check_collection");
+                                       data_string_forget (&data, MDL);
                                        classify (packet, nc);
                                        matched = 1;
                                        continue;
                                }
-                               if (!class -> spawning)
+                               if (!class -> spawning) {
+                                       data_string_forget (&data, MDL);
                                        continue;
+                               }
 #if defined (DEBUG_CLASS_MATCHING)
                                log_info ("spawning subclass %s.",
                                      print_hex_1 (data.len, data.data, 60));
 #endif
                                nc = (struct class *)
-                                       dmalloc (sizeof (struct class),
-                                                "class spawn");
+                                       dmalloc (sizeof (struct class), MDL);
                                memset (nc, 0, sizeof *nc);
                                nc -> group = class -> group;
                                nc -> superclass = class;
@@ -127,14 +125,16 @@ int check_collection (packet, lease, collection)
                                                (dmalloc
                                                 (nc -> lease_limit *
                                                  sizeof (struct lease *),
-                                                 "check_collection"));
+                                                 MDL));
                                        if (!nc -> billed_leases) {
                                                log_error ("no memory for%s",
                                                           " billing");
                                                data_string_forget
                                                        (&nc -> hash_string,
-                                                        "check_collection");
-                                               dfree (nc, "check_collection");
+                                                        MDL);
+                                               dfree (nc, MDL);
+                                               data_string_forget (&data,
+                                                                   MDL);
                                                continue;
                                        }
                                        memset (nc -> billed_leases, 0,
@@ -142,8 +142,8 @@ int check_collection (packet, lease, collection)
                                                 sizeof nc -> billed_leases));
                                }
                                data_string_copy (&nc -> hash_string, &data,
-                                                 "check_collection");
-                               data_string_forget (&data, "check_collection");
+                                                 MDL);
+                               data_string_forget (&data, MDL);
                                if (!class -> hash)
                                        class -> hash = new_hash ();
                                add_hash (class -> hash,
@@ -152,13 +152,12 @@ int check_collection (packet, lease, collection)
                                          (unsigned char *)nc);
                                classify (packet, nc);
                        }
-                       data_string_forget (&data, "check_collection");
                }
 
                status = (evaluate_boolean_expression_result
                          (&ignorep, packet, lease,
                           packet -> options, (struct option_state *)0,
-                          class -> expr));
+                          &lease -> scope, class -> expr));
                if (status) {
                        matched = 1;
 #if defined (DEBUG_CLASS_MATCHING)
index ccb35cf98adc5f6e0f669f3098c9d9176ead3dd2..797c0bae0142bc194ac3dd4e6faed21c0c7f4e7f 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: dhcp.c,v 1.132 2000/01/08 01:47:37 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: dhcp.c,v 1.133 2000/01/25 01:35:38 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -118,6 +118,10 @@ void dhcpdiscover (packet)
                }
        }
 
+       /* If it's an expired lease, get rid of any bindings. */
+       if (lease -> ends < cur_time && lease -> scope.bindings)
+               free_bindings (&lease -> scope, "dhcpdiscover");
+
        /* Set the lease to really expire in 2 minutes, unless it has
           not yet expired, in which case leave its expiry time alone. */
        when = cur_time + 120;
@@ -146,7 +150,7 @@ void dhcprequest (packet)
        if (oc &&
            evaluate_option_cache (&data, packet, (struct lease *)0,
                                   packet -> options, (struct option_state *)0,
-                                  oc)) {
+                                  &global_scope, oc, MDL)) {
                cip.len = 4;
                memcpy (cip.iabuf, data.data, 4);
                data_string_forget (&data, "dhcprequest");
@@ -304,7 +308,7 @@ void dhcprelease (packet)
        if (oc &&
            evaluate_option_cache (&data, packet, (struct lease *)0,
                                   packet -> options, (struct option_state *)0,
-                                  oc)) {
+                                  &global_scope, oc, MDL)) {
                lease = find_lease_by_uid (data.data, data.len);
                data_string_forget (&data, "dhcprelease");
 
@@ -316,10 +320,12 @@ void dhcprelease (packet)
                                break;
                        }
                }
-       } else {
-               /* The client is supposed to pass a valid client-identifier,
-                  but the spec on this has changed historically, so try the
-                  IP address in ciaddr if the client-identifier fails. */
+       }
+
+       /* The client is supposed to pass a valid client-identifier,
+          but the spec on this has changed historically, so try the
+          IP address in ciaddr if the client-identifier fails. */
+       if (!lease) {
                cip.len = 4;
                memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
                lease = find_lease_by_ip_addr (cip);
@@ -375,7 +381,7 @@ void dhcpdecline (packet)
        if (!evaluate_option_cache (&data, packet, (struct lease *)0,
                                    packet -> options,
                                    (struct option_state *)0,
-                                   oc))
+                                   &global_scope, oc, MDL))
                return;
 
        cip.len = 4;
@@ -388,24 +394,25 @@ void dhcpdecline (packet)
        /* Execute statements in scope starting with the subnet scope. */
        if (lease)
                execute_statements_in_scope (packet, (struct lease *)0,
-                                            packet -> options,
-                                            options, lease -> subnet -> group,
+                                            packet -> options, options,
+                                            &global_scope,
+                                            lease -> subnet -> group,
                                             (struct group *)0);
 
        /* Execute statements in the class scopes. */
        for (i = packet -> class_count; i > 0; i--) {
                execute_statements_in_scope
-                       (packet, (struct lease *)0, packet -> options,
-                        options, packet -> classes [i - 1] -> group,
+                       (packet, (struct lease *)0, packet -> options, options,
+                        &global_scope, packet -> classes [i - 1] -> group,
                         lease ? lease -> subnet -> group : (struct group *)0);
        }
 
        /* Drop the request if dhcpdeclines are being ignored. */
        oc = lookup_option (&server_universe, options, SV_DECLINES);
        if (!oc ||
-           evaluate_boolean_option_cache (&ignorep,
-                                          packet, lease, packet -> options,
-                                          options, oc)) {
+           evaluate_boolean_option_cache (&ignorep, packet, lease,
+                                          packet -> options, options,
+                                          &lease -> scope, oc, MDL)) {
                /* If we found a lease, mark it as unusable and complain. */
                if (lease) {
                        abandon_lease (lease, "declined.");
@@ -510,15 +517,15 @@ void dhcpinform (packet)
        /* Execute statements in scope starting with the subnet scope. */
        if (subnet)
                execute_statements_in_scope (packet, (struct lease *)0,
-                                            packet -> options,
-                                            options, subnet -> group,
+                                            packet -> options, options,
+                                            &global_scope, subnet -> group,
                                             (struct group *)0);
 
        /* Execute statements in the class scopes. */
        for (i = packet -> class_count; i > 0; i--) {
                execute_statements_in_scope
-                       (packet, (struct lease *)0, packet -> options,
-                        options, packet -> classes [i - 1] -> group,
+                       (packet, (struct lease *)0, packet -> options, options,
+                        &global_scope, packet -> classes [i - 1] -> group,
                         subnet ? subnet -> group : (struct group *)0);
        }
 
@@ -528,7 +535,7 @@ void dhcpinform (packet)
        if (oc &&
            evaluate_option_cache (&d1, packet, (struct lease *)0,
                                   packet -> options, (struct option_state *)0,
-                                  oc)) {
+                                  &global_scope, oc, MDL)) {
                i = d1.len;
                if (i > sizeof raw.file)
                        i = sizeof raw.file;
@@ -543,7 +550,7 @@ void dhcpinform (packet)
        if (oc &&
            evaluate_option_cache (&d1, packet, (struct lease *)0, 
                                   packet -> options, (struct option_state *)0,
-                                  oc)) {
+                                  &global_scope, oc, MDL)) {
                i = d1.len;
                if (i > sizeof raw.sname)
                        i = sizeof raw.sname;
@@ -560,7 +567,7 @@ void dhcpinform (packet)
                                 DHO_HOST_NAME))) {
                if (evaluate_option_cache (&d1, packet, (struct lease *)0, 
                                           packet -> options, options,
-                                          oc)) {
+                                          &global_scope, oc, MDL)) {
                        if (d1.data [d1.len - 1] == '\0')
                                nulltp = 1;
                        data_string_forget (&d1, "dhcpinform");
@@ -599,7 +606,8 @@ void dhcpinform (packet)
                from = packet -> interface -> primary_address;
        } else {
                if (evaluate_option_cache (&d1, packet, (struct lease *)0,
-                                          packet -> options, options, oc)) {
+                                          packet -> options, options,
+                                          &global_scope, oc, MDL)) {
                        if (!d1.len || d1.len != sizeof from) {
                                data_string_forget (&d1, "dhcpinform");
                                goto use_primary;
@@ -651,7 +659,8 @@ void dhcpinform (packet)
        if (!lookup_option (&dhcp_universe, options, i) &&
            (oc = lookup_option (&server_universe, options, j)) &&
            evaluate_option_cache (&d1, packet, (struct lease *)0,
-                                  packet -> options, options, oc)) {
+                                  packet -> options, options,
+                                  &global_scope, oc, MDL)) {
                oc = (struct option_cache *)0;
                if (option_cache_allocate (&oc, "dhcpinform")) {
                        if (make_encapsulation (&oc -> expression, &d1)) {
@@ -668,7 +677,8 @@ void dhcpinform (packet)
        i = SV_SITE_OPTION_SPACE;
        if ((oc = lookup_option (&server_universe, options, i)) &&
            evaluate_option_cache (&d1, packet, (struct lease *)0,
-                                  packet -> options, options, oc)) {
+                                  packet -> options, options,
+                                  &global_scope, oc, MDL)) {
                const struct universe *u;
                
                u = ((const struct universe *)
@@ -703,7 +713,8 @@ void dhcpinform (packet)
 
        if (oc)
                evaluate_option_cache (&prl, packet, (struct lease *)0,
-                                      packet -> options, options, oc);
+                                      packet -> options, options,
+                                      &global_scope, oc, MDL);
 
 #ifdef DEBUG_PACKET
        dump_packet (packet);
@@ -717,7 +728,8 @@ void dhcpinform (packet)
        if ((oc =
             lookup_option (&server_universe, options, SV_NEXT_SERVER))) {
                if (evaluate_option_cache (&d1, packet, (struct lease *)0,
-                                          packet -> options, options, oc)) {
+                                          packet -> options, options,
+                                          &global_scope, oc, MDL)) {
                        /* If there was more than one answer,
                           take the first. */
                        if (d1.len >= 4 && d1.data)
@@ -729,7 +741,8 @@ void dhcpinform (packet)
        /* Set up the option buffer... */
        outgoing.packet_length =
                cons_options (packet, outgoing.raw, (struct lease *)0,
-                             0, packet -> options, options, 0, nulltp, 0,
+                             0, packet -> options, options, &global_scope,
+                             0, nulltp, 0,
                              prl.len ? &prl : (struct data_string *)0);
        option_state_dereference (&options, "dhcpinform");
        data_string_forget (&prl, "dhcpinform");
@@ -839,8 +852,8 @@ void nak_lease (packet, cip)
        /* Set up the option buffer... */
        outgoing.packet_length =
                cons_options (packet, outgoing.raw, (struct lease *)0,
-                             0, packet -> options, options, 0, 0, 0,
-                             (struct data_string *)0);
+                             0, packet -> options, options, &global_scope,
+                             0, 0, 0, (struct data_string *)0);
        option_state_dereference (&options, "nak_lease");
 
 /*     memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/
@@ -966,8 +979,9 @@ void ack_lease (packet, lease, offer, when, msg)
        if (oc)
                s1 = evaluate_option_cache (&d1, packet, (struct lease *)0,
                                            packet -> options,
-                                           (struct option_state *)0, oc);
-       if (oc && status &&
+                                           (struct option_state *)0,
+                                           &global_scope, oc, MDL);
+       if (oc && s1 &&
            lease -> client_hostname &&
            strlen (lease -> client_hostname) == d1.len &&
            !memcmp (lease -> client_hostname, d1.data, d1.len)) {
@@ -1021,7 +1035,7 @@ void ack_lease (packet, lease, offer, when, msg)
        /* Execute statements in scope starting with the subnet scope. */
        execute_statements_in_scope (packet, lease,
                                     packet -> options,
-                                    state -> options,
+                                    state -> options, &lease -> scope,
                                     lease -> subnet -> group,
                                     (struct group *)0);
 
@@ -1029,7 +1043,7 @@ void ack_lease (packet, lease, offer, when, msg)
        if (lease -> pool)
                execute_statements_in_scope (packet, lease,
                                             packet -> options,
-                                            state -> options,
+                                            state -> options, &lease -> scope,
                                             lease -> pool -> group,
                                             lease -> subnet -> group);
 
@@ -1037,7 +1051,7 @@ void ack_lease (packet, lease, offer, when, msg)
        for (i = packet -> class_count; i > 0; i--) {
                execute_statements_in_scope
                        (packet, lease, packet -> options, state -> options,
-                        packet -> classes [i - 1] -> group,
+                        &lease -> scope, packet -> classes [i - 1] -> group,
                         (lease -> pool
                          ? lease -> pool -> group
                          : lease -> subnet -> group));
@@ -1047,7 +1061,7 @@ void ack_lease (packet, lease, offer, when, msg)
           with its group. */
        if (lease -> host)
                execute_statements_in_scope (packet, lease, packet -> options,
-                                            state -> options,
+                                            state -> options, &lease -> scope,
                                             lease -> host -> group,
                                             (lease -> pool
                                              ? lease -> pool -> group
@@ -1067,7 +1081,8 @@ void ack_lease (packet, lease, offer, when, msg)
                                 SV_ONE_LEASE_PER_CLIENT)) &&
            evaluate_boolean_option_cache (&ignorep,
                                           packet, lease, packet -> options,
-                                          state -> options, oc)) {
+                                          state -> options, &lease -> scope,
+                                          oc, MDL)) {
                struct lease *seek;
                if (lease -> uid_len) {
                        do {
@@ -1093,7 +1108,9 @@ void ack_lease (packet, lease, offer, when, msg)
                                          SV_DUPLICATES)) &&
                     !evaluate_boolean_option_cache (&ignorep, packet, lease,
                                                     packet -> options,
-                                                    state -> options, oc))) {
+                                                    state -> options,
+                                                    &lease -> scope,
+                                                    oc, MDL))) {
                        do {
                                seek = (find_lease_by_hw_addr
                                        (lease -> hardware_addr.hbuf,
@@ -1119,11 +1136,11 @@ void ack_lease (packet, lease, offer, when, msg)
                                 SV_MIN_SECS))) {
                if (evaluate_option_cache (&d1, packet, lease,
                                           packet -> options, state -> options,
-                                          oc)) {
+                                          &lease -> scope, oc, MDL)) {
                        if (d1.len && packet -> raw -> secs < d1.data [0]) {
-                               data_string_forget (&d1, "ack_lease");
                                log_info ("%s: %d secs < %d", msg,
                                          packet -> raw -> secs, d1.data [0]);
+                               data_string_forget (&d1, "ack_lease");
                                free_lease_state (state, "ack_lease");
                                static_lease_dereference (lease, "ack_lease");
                                return;
@@ -1146,7 +1163,7 @@ void ack_lease (packet, lease, offer, when, msg)
                if (oc &&
                    evaluate_option_cache (&d1, packet, lease,
                                           packet -> options, state -> options,
-                                          oc)) {
+                                          &lease -> scope, oc, MDL)) {
                        hp = find_hosts_by_uid (d1.data, d1.len);
                        data_string_forget (&d1, "dhcpdiscover");
                        if (!hp)
@@ -1170,7 +1187,8 @@ void ack_lease (packet, lease, offer, when, msg)
                                 SV_BOOT_UNKNOWN_CLIENTS)) &&
            !evaluate_boolean_option_cache (&ignorep,
                                            packet, lease, packet -> options,
-                                           state -> options, oc)) {
+                                           state -> options,
+                                           &lease -> scope, oc, MDL)) {
                if (!ignorep)
                        log_info ("%s: unknown client", msg);
                free_lease_state (state, "ack_lease");
@@ -1184,7 +1202,8 @@ void ack_lease (packet, lease, offer, when, msg)
                                   SV_ALLOW_BOOTP)) &&
            !evaluate_boolean_option_cache (&ignorep,
                                            packet, lease, packet -> options,
-                                           state -> options, oc)) {
+                                           state -> options,
+                                           &lease -> scope, oc, MDL)) {
                if (!ignorep)
                        log_info ("%s: bootp disallowed", msg);
                free_lease_state (state, "ack_lease");
@@ -1198,7 +1217,8 @@ void ack_lease (packet, lease, offer, when, msg)
        if (oc &&
            !evaluate_boolean_option_cache (&ignorep,
                                            packet, lease, packet -> options,
-                                           state -> options, oc)) {
+                                           state -> options,
+                                           &lease -> scope, oc, MDL)) {
                if (!ignorep)
                        log_info ("%s: booting disallowed", msg);
                free_lease_state (state, "ack_lease");
@@ -1253,7 +1273,7 @@ void ack_lease (packet, lease, offer, when, msg)
        if (oc)
                evaluate_option_cache (&state -> filename, packet, lease,
                                       packet -> options, state -> options,
-                                      oc);
+                                      &lease -> scope, oc, MDL);
 
        /* Choose a server name as above. */
        oc = lookup_option (&server_universe, state -> options,
@@ -1261,7 +1281,7 @@ void ack_lease (packet, lease, offer, when, msg)
        if (oc)
                evaluate_option_cache (&state -> server_name, packet, lease,
                                       packet -> options, state -> options,
-                                      oc);
+                                      &lease -> scope, oc, MDL);
 
        /* At this point, we have a lease that we can offer the client.
           Now we construct a lease structure that contains what we want,
@@ -1283,7 +1303,8 @@ void ack_lease (packet, lease, offer, when, msg)
                                         SV_DEFAULT_LEASE_TIME))) {
                        if (evaluate_option_cache (&d1, packet, lease,
                                                   packet -> options,
-                                                  state -> options, oc)) {
+                                                  state -> options,
+                                                  &lease -> scope, oc, MDL)) {
                                if (d1.len == sizeof (u_int32_t))
                                        default_lease_time =
                                                getULong (d1.data);
@@ -1295,7 +1316,8 @@ void ack_lease (packet, lease, offer, when, msg)
                                         DHO_DHCP_LEASE_TIME)))
                        s1 = evaluate_option_cache (&d1, packet, lease,
                                                    packet -> options,
-                                                   state -> options, oc);
+                                                   state -> options,
+                                                   &lease -> scope, oc, MDL);
                else
                        s1 = 0;
                if (s1 && d1.len == sizeof (u_int32_t)) {
@@ -1313,7 +1335,8 @@ void ack_lease (packet, lease, offer, when, msg)
                                         SV_MAX_LEASE_TIME))) {
                        if (evaluate_option_cache (&d1, packet, lease,
                                                   packet -> options,
-                                                  state -> options, oc)) {
+                                                  state -> options,
+                                                  &lease -> scope, oc, MDL)) {
                                if (d1.len == sizeof (u_int32_t))
                                        max_lease_time =
                                                getULong (d1.data);
@@ -1334,7 +1357,8 @@ void ack_lease (packet, lease, offer, when, msg)
                                         SV_MIN_LEASE_TIME))) {
                        if (evaluate_option_cache (&d1, packet, lease,
                                                   packet -> options,
-                                                  state -> options, oc)) {
+                                                  state -> options,
+                                                  &lease -> scope, oc, MDL)) {
                                if (d1.len == sizeof (u_int32_t))
                                        min_lease_time = getULong (d1.data);
                                data_string_forget (&d1, "ack_lease");
@@ -1405,7 +1429,7 @@ void ack_lease (packet, lease, offer, when, msg)
                        if (evaluate_option_cache (&d1, packet, lease,
                                                   packet -> options,
                                                   state -> options,
-                                                  oc)) {
+                                                  &lease -> scope, oc, MDL)) {
                                if (d1.len == sizeof (u_int32_t))
                                        lease_time = getULong (d1.data);
                                data_string_forget (&d1, "ack_lease");
@@ -1417,7 +1441,7 @@ void ack_lease (packet, lease, offer, when, msg)
                        if (evaluate_option_cache (&d1, packet, lease,
                                                   packet -> options,
                                                   state -> options,
-                                                  oc)) {
+                                                  &lease -> scope, oc, MDL)) {
                                if (d1.len == sizeof (u_int32_t))
                                        lease_time = (getULong (d1.data) -
                                                      cur_time);
@@ -1436,7 +1460,8 @@ void ack_lease (packet, lease, offer, when, msg)
                            DHO_DHCP_CLIENT_IDENTIFIER);
        if (oc &&
            evaluate_option_cache (&d1, packet, lease,
-                                  packet -> options, state -> options, oc)) {
+                                  packet -> options, state -> options,
+                                  &lease -> scope, oc, MDL)) {
                if (d1.len <= sizeof lt.uid_buf) {
                        memcpy (lt.uid_buf, d1.data, d1.len);
                        lt.uid = lt.uid_buf;
@@ -1478,11 +1503,17 @@ void ack_lease (packet, lease, offer, when, msg)
           committed, execute them. */
        if (lease -> on_commit && (!offer || offer == DHCPACK)) {
                execute_statements (packet, lease, packet -> options,
-                                   state -> options, lease -> on_commit);
-               executable_statement_dereference (&lease -> on_commit,
-                                                 "ack_lease");
+                                   state -> options, &lease -> scope,
+                                   lease -> on_commit);
+               if (lease -> on_commit)
+                       executable_statement_dereference (&lease -> on_commit,
+                                                         "ack_lease");
        }
 
+       /* Save any bindings. */
+       lt.scope.bindings = lease -> scope.bindings;
+       lease -> scope.bindings = (struct binding *)0;
+
        /* Don't call supersede_lease on a mocked-up lease. */
        if (lease -> flags & STATIC_LEASE) {
                /* Copy the hardware address into the static lease
@@ -1544,7 +1575,7 @@ void ack_lease (packet, lease, offer, when, msg)
                                SV_ALWAYS_BROADCAST)) &&
            evaluate_boolean_option_cache (&ignorep, packet, lease,
                                           packet -> options, state -> options,
-                                          oc))
+                                          &lease -> scope, oc, MDL))
                state -> bootp_flags |= htons (BOOTP_BROADCAST);
 
        /* Get the Maximum Message Size option from the packet, if one
@@ -1553,7 +1584,8 @@ void ack_lease (packet, lease, offer, when, msg)
                            DHO_DHCP_MAX_MESSAGE_SIZE);
        if (oc &&
            evaluate_option_cache (&d1, packet, lease,
-                                  packet -> options, state -> options, oc)) {
+                                  packet -> options, state -> options,
+                                  &lease -> scope, oc, MDL)) {
                if (d1.len == sizeof (u_int16_t))
                        state -> max_message_size = getUShort (d1.data);
                data_string_forget (&d1, "ack_lease");
@@ -1601,7 +1633,8 @@ void ack_lease (packet, lease, offer, when, msg)
                } else {
                        if (evaluate_option_cache (&d1, packet, lease,
                                                   packet -> options,
-                                                  state -> options, oc)) {
+                                                  state -> options,
+                                                  &lease -> scope, oc, MDL)) {
                                if (!d1.len ||
                                    d1.len > sizeof state -> from.iabuf) {
                                        data_string_forget (&d1, "ack_lease");
@@ -1691,7 +1724,7 @@ void ack_lease (packet, lease, offer, when, msg)
                            state -> options, SV_NEXT_SERVER))) {
                if (evaluate_option_cache (&d1, packet, lease,
                                           packet -> options, state -> options,
-                                          oc)) {
+                                          &lease -> scope, oc, MDL)) {
                        /* If there was more than one answer,
                           take the first. */
                        if (d1.len >= 4 && d1.data)
@@ -1726,8 +1759,8 @@ void ack_lease (packet, lease, offer, when, msg)
            lease -> host && lease -> host -> name &&
            (evaluate_boolean_option_cache
             (&ignorep, packet, lease, packet -> options, state -> options,
-             (lookup_option
-              (&server_universe, state -> options, j))))) {
+             &lease -> scope,
+             lookup_option (&server_universe, state -> options, j), MDL))) {
                oc = (struct option_cache *)0;
                if (option_cache_allocate (&oc, "ack_lease")) {
                        if (make_const_data (&oc -> expression,
@@ -1749,7 +1782,8 @@ void ack_lease (packet, lease, offer, when, msg)
        if (!lookup_option (&server_universe, state -> options, i) &&
            (evaluate_boolean_option_cache
             (&ignorep, packet, lease, packet -> options, state -> options,
-             lookup_option (&server_universe, state -> options, j)))) {
+             &lease -> scope, lookup_option (&server_universe,
+                                               state -> options, j), MDL))) {
                struct in_addr ia;
                struct hostent *h;
                
@@ -1782,8 +1816,9 @@ void ack_lease (packet, lease, offer, when, msg)
 
        if (evaluate_boolean_option_cache
            (&ignorep, packet, lease, packet -> options, state -> options,
+            &lease -> scope,
             lookup_option (&server_universe, state -> options,
-                           SV_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE))) {
+                           SV_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE), MDL)) {
                i = DHO_ROUTERS;
                oc = lookup_option (&dhcp_universe, state -> options, i);
                if (!oc) {
@@ -1830,7 +1865,8 @@ void ack_lease (packet, lease, offer, when, msg)
        if (!lookup_option (&dhcp_universe, state -> options, i) &&
            (oc = lookup_option (&server_universe, state -> options, j)) &&
            evaluate_option_cache (&d1, packet, lease,
-                                  packet -> options, state -> options, oc)) {
+                                  packet -> options, state -> options,
+                                  &lease -> scope, oc, MDL)) {
                oc = (struct option_cache *)0;
                if (option_cache_allocate (&oc, "ack_lease")) {
                        if (make_encapsulation (&oc -> expression, &d1)) {
@@ -1848,7 +1884,8 @@ void ack_lease (packet, lease, offer, when, msg)
        i = SV_SITE_OPTION_SPACE;
        if ((oc = lookup_option (&server_universe, state -> options, i)) &&
            evaluate_option_cache (&d1, packet, lease,
-                                  packet -> options, state -> options, oc)) {
+                                  packet -> options, state -> options,
+                                  &lease -> scope, oc, MDL)) {
                const struct universe *u;
                
                u = ((const struct universe *)
@@ -1881,7 +1918,7 @@ void ack_lease (packet, lease, offer, when, msg)
                evaluate_option_cache (&state -> parameter_request_list,
                                       packet, lease,
                                       packet -> options, state -> options,
-                                      oc);
+                                      &lease -> scope, oc, MDL);
 
 #ifdef DEBUG_PACKET
        dump_packet (packet);
@@ -1984,7 +2021,7 @@ void dhcp_reply (lease)
        packet_length = cons_options (state -> packet, &raw, lease,
                                      state -> max_message_size,
                                      state -> packet -> options,
-                                     state -> options,
+                                     state -> options, &global_scope,
                                      bufs, nulltp, bootpp,
                                      &state -> parameter_request_list);
 
@@ -2056,8 +2093,6 @@ void dhcp_reply (lease)
                                              raw.siaddr, &to,
                                              (struct hardware *)0);
 
-                       data_string_forget (&state -> parameter_request_list,
-                                           "dhcp_reply");
                        free_lease_state (state, "dhcp_reply fallback 1");
                        lease -> state = (struct lease_state *)0;
                        return;
@@ -2090,8 +2125,6 @@ void dhcp_reply (lease)
                                              &raw, packet_length,
                                              raw.siaddr, &to,
                                              (struct hardware *)0);
-                       data_string_forget (&state -> parameter_request_list,
-                                           "dhcp_reply");
                        free_lease_state (state, "dhcp_reply fallback 2");
                        lease -> state = (struct lease_state *)0;
                        return;
@@ -2121,8 +2154,6 @@ void dhcp_reply (lease)
        /* Free all of the entries in the option_state structure
           now that we're done with them. */
 
-       data_string_forget (&state -> parameter_request_list,
-                           "dhcp_reply");
        free_lease_state (state, "dhcp_reply");
        lease -> state = (struct lease_state *)0;
 }
@@ -2150,7 +2181,7 @@ struct lease *find_lease (packet, share, ours)
        if (oc &&
            evaluate_option_cache (&d1, packet, (struct lease *)0,
                                   packet -> options, (struct option_state *)0,
-                                  oc)) {
+                                  &global_scope, oc, MDL)) {
                packet -> got_requested_address = 1;
                cip.len = 4;
                memcpy (cip.iabuf, d1.data, cip.len);
@@ -2170,7 +2201,7 @@ struct lease *find_lease (packet, share, ours)
            evaluate_option_cache (&client_identifier,
                                   packet, (struct lease *)0,
                                   packet -> options, (struct option_state *)0,
-                                  oc)) {
+                                  &global_scope, oc, MDL)) {
                /* Remember this for later. */
                have_client_identifier = 1;
 
@@ -2401,13 +2432,13 @@ struct lease *find_lease (packet, share, ours)
                        if (uid_lease) {
                            if (uid_lease -> ends > cur_time) {
                                log_error ("client %s has duplicate%s on %s",
-                                          " leases",
                                           (print_hw_addr
                                            (packet -> raw -> htype,
                                             packet -> raw -> hlen,
                                             packet -> raw -> chaddr)),
-                                     (ip_lease -> subnet ->
-                                      shared_network -> name));
+                                          " leases",
+                                          (ip_lease -> subnet ->
+                                           shared_network -> name));
 
                                /* If the client is REQUESTing the lease,
                                   it shouldn't still be using the old
@@ -2655,6 +2686,8 @@ void static_lease_dereference (lease, name)
                executable_statement_dereference (&lease -> on_expiry, name);
        if (lease -> on_commit)
                executable_statement_dereference (&lease -> on_commit, name);
+       if (&lease -> scope)
+               free_bindings (&lease -> scope, name);
 }
 
 /* Look through all the pools in a list starting with the specified pool