]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
Pass client state to eval functions. Lots of other stuff.
authorTed Lemon <source@isc.org>
Tue, 28 Nov 2000 23:27:24 +0000 (23:27 +0000)
committerTed Lemon <source@isc.org>
Tue, 28 Nov 2000 23:27:24 +0000 (23:27 +0000)
server/bootp.c
server/class.c
server/confpars.c
server/db.c
server/dhcp.c
server/dhcpd.c
server/failover.c
server/mdb.c
server/omapi.c
server/stables.c

index 87176ecdf86ecc85465feff3153cb34df7f21c26..b32e27bd1feabafb238471990b1d99f5def47c7a 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: bootp.c,v 1.67 2000/10/10 23:01:05 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: bootp.c,v 1.68 2000/11/28 23:27:13 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -93,7 +93,8 @@ void bootp (packet)
                             packet -> raw -> hlen, MDL);
 
        lease  = (struct lease *)0;
-       find_lease (&lease, packet, packet -> shared_network, 0, 0, MDL);
+       find_lease (&lease, packet, packet -> shared_network,
+                   0, 0, (struct lease *)0, MDL);
 
        /* Find an IP address in the host_decl that matches the
           specified network. */
@@ -156,7 +157,8 @@ void bootp (packet)
        
        /* Execute the subnet statements. */
        execute_statements_in_scope ((struct binding_value **)0,
-                                    packet, lease, packet -> options, options,
+                                    packet, lease, (struct client_state *)0,
+                                    packet -> options, options,
                                     &lease -> scope, lease -> subnet -> group,
                                     (struct group *)0);
        
@@ -164,20 +166,23 @@ void bootp (packet)
        for (i = packet -> class_count; i > 0; i--) {
                execute_statements_in_scope
                        ((struct binding_value **)0,
-                        packet, lease, packet -> options, options,
+                        packet, lease, (struct client_state *)0,
+                        packet -> options, options,
                         &lease -> scope, packet -> classes [i - 1] -> group,
                         lease -> subnet -> group);
        }
 
        /* Execute the host statements. */
        execute_statements_in_scope ((struct binding_value **)0,
-                                    packet, lease, packet -> options, options,
+                                    packet, lease, (struct client_state *)0,
+                                    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,
+                                           (struct client_state *)0,
                                            packet -> options, options,
                                            &lease -> scope, oc, MDL)) {
                if (!ignorep)
@@ -188,6 +193,7 @@ void bootp (packet)
        if ((oc = lookup_option (&server_universe,
                                 options, SV_ALLOW_BOOTING)) &&
            !evaluate_boolean_option_cache (&ignorep, packet, lease,
+                                           (struct client_state *)0,
                                            packet -> options, options,
                                            &lease -> scope, oc, MDL)) {
                if (!ignorep)
@@ -204,8 +210,8 @@ void bootp (packet)
           just copy the input options to the output. */
        if (!packet -> options_valid &&
            !(evaluate_boolean_option_cache
-             (&ignorep, packet, lease, packet -> options, options,
-              &lease -> scope,
+             (&ignorep, packet, lease, (struct client_state *)0,
+              packet -> options, options, &lease -> scope,
               lookup_option (&server_universe, options,
                              SV_ALWAYS_REPLY_RFC1048), MDL))) {
                memcpy (outgoing.raw -> options,
@@ -238,7 +244,8 @@ void bootp (packet)
                   name buffers. */
 
                outgoing.packet_length =
-                       cons_options (packet, outgoing.raw, lease, 0,
+                       cons_options (packet, outgoing.raw, lease,
+                                     (struct client_state *)0, 0,
                                      packet -> options, options,
                                      &lease -> scope,
                                      0, 0, 1, (struct data_string *)0,
@@ -264,6 +271,7 @@ void bootp (packet)
        if ((oc = lookup_option (&server_universe,
                                options, SV_ALWAYS_BROADCAST)) &&
            evaluate_boolean_option_cache (&ignorep, packet, lease,
+                                          (struct client_state *)0,
                                           packet -> options, options,
                                           &lease -> scope, oc, MDL))
                raw.flags |= htons (BOOTP_BROADCAST);
@@ -273,6 +281,7 @@ void bootp (packet)
        oc = lookup_option (&server_universe, options, SV_NEXT_SERVER);
        if (oc &&
            evaluate_option_cache (&d1, packet, lease,
+                                  (struct client_state *)0,
                                   packet -> options, options,
                                   &lease -> scope, oc, MDL)) {
                /* If there was more than one answer, take the first. */
@@ -293,6 +302,7 @@ void bootp (packet)
        oc = lookup_option (&server_universe, options, SV_FILENAME);
        if (oc &&
            evaluate_option_cache (&d1, packet, lease,
+                                  (struct client_state *)0,
                                   packet -> options, options,
                                   &lease -> scope, oc, MDL)) {
                memcpy (raw.file, d1.data,
@@ -308,6 +318,7 @@ void bootp (packet)
        oc = lookup_option (&server_universe, options, SV_SERVER_NAME);
        if (oc &&
            evaluate_option_cache (&d1, packet, lease,
+                                  (struct client_state *)0,
                                   packet -> options, options,
                                   &lease -> scope, oc, MDL)) {
                memcpy (raw.sname, d1.data,
@@ -320,7 +331,8 @@ void bootp (packet)
 
        /* Execute the commit statements, if there are any. */
        execute_statements ((struct binding_value **)0,
-                           packet, lease, packet -> options,
+                           packet, lease, (struct client_state *)0,
+                           packet -> options,
                            options, &lease -> scope, lease -> on_commit);
 
        /* We're done with the option state. */
index ad08b2cc38a617b92d180bc31fcdf6f18593691d..b1b0621f8db6931679f08a5731554a110161f6a7 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: class.c,v 1.26 2000/09/30 01:31:09 mellon Exp $ Copyright (c) 1998-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: class.c,v 1.27 2000/11/28 23:27:14 mellon Exp $ Copyright (c) 1998-2000 The Internet Software Consortium.  All rights reserved.\n";
 
 #endif /* not lint */
 
@@ -84,10 +84,10 @@ void classification_setup ()
 void classify_client (packet)
        struct packet *packet;
 {
-       execute_statements ((struct binding_value **)0,
-                           packet, (struct lease *)0, packet -> options,
-                           (struct option_state *)0, &global_scope,
-                           default_classification_rules);
+       execute_statements ((struct binding_value **)0, packet,
+                           (struct lease *)0, (struct client_state *)0,
+                           packet -> options, (struct option_state *)0,
+                           &global_scope, default_classification_rules);
 }
 
 int check_collection (packet, lease, collection)
@@ -116,6 +116,7 @@ int check_collection (packet, lease, collection)
                if (class -> expr) {
                        status = (evaluate_boolean_expression_result
                                  (&ignorep, packet, lease,
+                                  (struct client_state *)0,
                                   packet -> options, (struct option_state *)0,
                                   lease ? &lease -> scope : &global_scope,
                                   class -> expr));
@@ -138,6 +139,7 @@ int check_collection (packet, lease, collection)
                if (class -> submatch) {
                        status = (evaluate_data_expression
                                  (&data, packet, lease,
+                                  (struct client_state *)0,
                                   packet -> options, (struct option_state *)0,
                                   lease ? &lease -> scope : &global_scope,
                                   class -> submatch));
index c197e288bffaf3b321b89fb4bc0a219275d1fe65..9281f63c99bd67f195005ad2a258305613fbce93 100644 (file)
@@ -1,3 +1,4 @@
+XXX Do tokens for client states!
 /* confpars.c
 
    Parser for dhcpd config file... */
@@ -43,7 +44,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: confpars.c,v 1.126 2000/09/01 19:35:38 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: confpars.c,v 1.127 2000/11/28 23:27:15 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -1728,14 +1729,20 @@ int parse_class_declaration (cp, cfile, group, type)
                        if (token != IF)
                                goto submatch;
                        token = next_token (&val, cfile);
-                       parse_boolean_expression (&class -> expr, cfile,
-                                                 &lose);
-                       if (lose)
-                               break;
+                       if (!parse_boolean_expression (&class -> expr, cfile,
+                                                      &lose)) {
+                               if (!lose) {
+                                       parse_warn (cfile,
+                                                   "expecting boolean expr.");
+                                       skip_to_semi (cfile);
+                               }
+                       } else {
 #if defined (DEBUG_EXPRESSION_PARSE)
-                       print_expression ("class match", class -> expr);
+                               print_expression ("class match",
+                                                 class -> expr);
 #endif
-                       parse_semi (cfile);
+                               parse_semi (cfile);
+                       }
                } else if (token == SPAWN) {
                        if (pc) {
                                parse_warn (cfile,
@@ -1760,15 +1767,20 @@ int parse_class_declaration (cp, cfile, group, type)
                                skip_to_semi (cfile);
                                break;
                        }
-                       parse_data_expression (&class -> submatch,
-                                              cfile, &lose);
-                       if (lose)
-                               break;
+                       if (!parse_data_expression (&class -> submatch,
+                                                   cfile, &lose)) {
+                               if (!lose) {
+                                       parse_warn (cfile,
+                                                   "expecting data expr.");
+                                       skip_to_semi (cfile);
+                               }
+                       } else {
 #if defined (DEBUG_EXPRESSION_PARSE)
-                       print_expression ("class submatch",
-                                         class -> submatch);
+                               print_expression ("class submatch",
+                                                 class -> submatch);
 #endif
-                       parse_semi (cfile);
+                               parse_semi (cfile);
+                       }
                } else if (token == LEASE) {
                        next_token (&val, cfile);
                        token = next_token (&val, cfile);
@@ -2217,6 +2229,7 @@ int parse_lease_declaration (struct lease **lp, struct parse *cfile)
        struct binding *binding;
        isc_result_t status;
        binding_state_t *statep;
+       struct option_cache *oc, *optr;
 
        lease = (struct lease *)0;
        status = lease_allocate (&lease, MDL);
@@ -2524,6 +2537,33 @@ int parse_lease_declaration (struct lease **lp, struct parse *cfile)
                        executable_statement_dereference (&on, MDL);
                        break;
                        
+                     case OPTION:
+                       noequal = 0;
+                       seenbit = 0;
+                       oc = (struct option_cache *)0;
+                       if (parse_option_decl (&oc, cfile)) {
+                               if (oc -> option -> universe !=
+                                   &agent_universe) {
+                                       parse_warn (cfile,
+                                                   "agent option expected.");
+                                       option_cache_dereference (&oc, MDL);
+                                       break;
+                               }
+                               if (lease -> agent_options) {
+                                       for (optr = lease -> agent_options;
+                                            optr -> next;
+                                            optr = optr -> next)
+                                               ;
+                                       option_cache_reference (&optr -> next,
+                                                               oc, MDL);
+                               } else
+                                       option_cache_reference
+                                               (&lease -> agent_options,
+                                                oc, MDL);
+                               option_cache_dereference (&oc, MDL);
+                       }
+                       break;
+
                      case TOKEN_SET:
                        noequal = 0;
                        
index 9ec9dc6a74a51eeacfa559546a207dd0be28c612..e2134908bfa44177f7938ae67797ae04587de8cb 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: db.c,v 1.58 2000/09/04 22:28:38 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: db.c,v 1.59 2000/11/28 23:27:16 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -260,6 +260,25 @@ int write_lease (lease)
                }
            }
        }
+       if (lease -> agent_options) {
+               struct option_cache *oc;
+               struct data_string ds;
+
+               memset (&ds, 0, sizeof ds);
+               for (oc = lease -> agent_options; oc; oc = oc -> next) {
+                       if (oc -> data.len) {
+                               errno = 0;
+                               fprintf (db_file, "\n  option agent.%s %s;",
+                                        oc -> option -> name,
+                                        pretty_print_option (oc -> option,
+                                                             oc -> data.data,
+                                                             oc -> data.len,
+                                                             1, 1));
+                               if (errno)
+                                       ++errors;
+                       }
+               }
+       }
        if (lease -> client_hostname &&
            db_printable (lease -> client_hostname)) {
                errno = 0;
@@ -384,6 +403,7 @@ int write_host (host)
                if (host -> fixed_addr &&
                    evaluate_option_cache (&ip_addrs, (struct packet *)0,
                                           (struct lease *)0,
+                                          (struct client_state *)0,
                                           (struct option_state *)0,
                                           (struct option_state *)0,
                                           &global_scope,
index e2273d464861344d745a9dec0b78f4589675fd37..5bf5667df295bbaed970f70d829f8366efb80966 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: dhcp.c,v 1.169 2000/10/13 18:58:12 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: dhcp.c,v 1.170 2000/11/28 23:27:17 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -57,9 +57,146 @@ void dhcp (packet)
 {
        int ms_nulltp = 0;
        struct option_cache *oc;
+       struct lease *lease = (struct lease *)0;
+       const char *errmsg;
+       struct data_string data;
 
-       if (!locate_network (packet) && packet -> packet_type != DHCPREQUEST)
-               return;
+       if (!locate_network (packet) &&
+           packet -> packet_type != DHCPREQUEST &&
+           packet -> packet_type != DHCPINFORM) {
+               static const char *dhcp_type_names [] = { 
+                       "DHCPDISCOVER",
+                       "DHCPOFFER",
+                       "DHCPREQUEST",
+                       "DHCPDECLINE",
+                       "DHCPACK",
+                       "DHCPNAK",
+                       "DHCPRELEASE",
+                       "DHCPINFORM"
+               };
+               const int dhcp_type_name_max = ((sizeof dhcp_type_names) / 
+                                               sizeof (char *));
+               const char *s;
+               char typebuf [32];
+               errmsg = "unknown network segment";
+             bad_packet:
+               
+               if (packet -> packet_type > 0 &&
+                   packet -> packet_type < dhcp_type_name_max - 1) {
+                       s = dhcp_type_names [packet -> packet_type - 1];
+               } else {
+#if defined (HAVE_SNPRINTF)
+                       snprintf (typebuf, sizeof typebuf,
+                                 "type %d", packet -> packet_type);
+#else
+                       sprintf (typebuf, 
+                                 "type %d", packet -> packet_type);
+#endif
+                       s = typebuf;
+               }
+               
+               log_info ("%s from %s via %s: %s", s,
+                         (packet -> raw -> htype
+                          ? print_hw_addr (packet -> raw -> htype,
+                                           packet -> raw -> hlen,
+                                           packet -> raw -> chaddr)
+                          : "<no identifier>"),
+                         packet -> raw -> giaddr.s_addr
+                         ? inet_ntoa (packet -> raw -> giaddr)
+                         : packet -> interface -> name, errmsg);
+               goto out;
+       }
+
+       /* There is a problem with the relay agent information option,
+          which is that in order for a normal relay agent to append
+          this option, the relay agent has to have been involved in
+          getting the packet from the client to the server.  Note
+          that this is the software entity known as the relay agent,
+          _not_ the hardware entity known as a router in which the
+          relay agent may be running, so the fact that a router has
+          forwarded a packet does not mean that the relay agent in
+          the router was involved.
+
+          So when the client is in INIT or INIT-REBOOT or REBINDING
+          state, the relay agent gets to tack on its options, but
+          when it's not, the relay agent doesn't get to do this,
+          which means that any decisions the DHCP server may make
+          based on the agent options will be made incorrectly.  
+
+          We work around this in the following way: if this is a
+          DHCPREQUEST and doesn't have relay agent information
+          options, we see if there's an existing lease for this IP
+          address and this client that _does_ have stashed agent
+          options.   If so, then we tack those options onto the
+          packet as if they came from the client.   Later on, when we
+          are deciding whether to steal the agent options from the
+          packet, if the agent options stashed on the lease are the
+          same as those stashed on the packet, we don't steal them -
+          this ensures that the client never receives its agent
+          options. */
+
+       if (packet -> packet_type == DHCPREQUEST &&
+           packet -> raw -> ciaddr.s_addr &&
+           !packet -> raw -> giaddr.s_addr &&
+           (packet -> options -> universe_count < agent_universe.index ||
+            !packet -> options -> universes [agent_universe.index]))
+       {
+               struct iaddr cip;
+
+               cip.len = sizeof packet -> raw -> ciaddr;
+               memcpy (cip.iabuf, &packet -> raw -> ciaddr,
+                       sizeof packet -> raw -> ciaddr);
+               if (!find_lease_by_ip_addr (&lease, cip, MDL))
+                       goto nolease;
+
+               /* If there are no agent options on the lease, it's not
+                  interesting. */
+               if (!lease -> agent_options)
+                       goto nolease;
+
+               /* The client should not be unicasting a renewal if its lease
+                  has expired, so make it go through the process of getting
+                  its agent options legally. */
+               if (lease -> ends < cur_time)
+                       goto nolease;
+
+               if (lease -> uid_len) {
+                       oc = lookup_option (&dhcp_universe, packet -> options,
+                                           DHO_DHCP_CLIENT_IDENTIFIER);
+                       if (!oc)
+                               goto nolease;
+
+                       memset (&data, 0, sizeof data);
+                       if (!evaluate_option_cache (&data,
+                                                   packet, (struct lease *)0,
+                                                   (struct client_state *)0,
+                                                   packet -> options,
+                                                   (struct option_state *)0,
+                                                   &global_scope, oc, MDL))
+                               goto nolease;
+                       if (lease -> uid_len != data.len ||
+                           memcmp (lease -> uid, data.data, data.len)) {
+                               data_string_forget (&data, MDL);
+                               goto nolease;
+                       }
+                       data_string_forget (&data, MDL);
+               } else
+                       if ((lease -> hardware_addr.hbuf [0] !=
+                            packet -> raw -> htype) ||
+                           (lease -> hardware_addr.hlen - 1 !=
+                            packet -> raw -> hlen) ||
+                           memcmp (&lease -> hardware_addr.hbuf [1],
+                                   packet -> raw -> chaddr,
+                                   packet -> raw -> hlen))
+                               goto nolease;
+
+               /* Okay, so we found a lease that matches the client. */
+               option_cache_reference ((struct option_cache **)
+                                       &(packet -> options -> universes
+                                         [agent_universe.index]),
+                                       lease -> agent_options, MDL);
+       }
+      nolease:
 
        /* Classify the client. */
        if ((oc = lookup_option (&dhcp_universe, packet -> options,
@@ -80,7 +217,7 @@ void dhcp (packet)
                break;
 
              case DHCPREQUEST:
-               dhcprequest (packet, ms_nulltp);
+               dhcprequest (packet, ms_nulltp, lease);
                break;
 
              case DHCPRELEASE:
@@ -95,9 +232,19 @@ void dhcp (packet)
                dhcpinform (packet, ms_nulltp);
                break;
 
-             default:
+
+             case DHCPACK:
+             case DHCPOFFER:
+             case DHCPNAK:
                break;
+
+             default:
+               errmsg = "unknown packet type";
+               goto bad_packet;
        }
+      out:
+       if (lease)
+               lease_dereference (&lease, MDL);
 }
 
 void dhcpdiscover (packet, ms_nulltp)
@@ -115,7 +262,7 @@ void dhcpdiscover (packet, ms_nulltp)
 #endif
 
        find_lease (&lease, packet, packet -> shared_network,
-                   0, &allocatedp, MDL);
+                   0, &allocatedp, (struct lease *)0, MDL);
 
        if (lease && lease -> client_hostname &&
            db_printable (lease -> client_hostname))
@@ -216,9 +363,10 @@ void dhcpdiscover (packet, ms_nulltp)
                lease_dereference (&lease, MDL);
 }
 
-void dhcprequest (packet, ms_nulltp)
+void dhcprequest (packet, ms_nulltp, ip_lease)
        struct packet *packet;
        int ms_nulltp;
+       struct lease *ip_lease;
 {
        struct lease *lease;
        struct iaddr cip;
@@ -238,6 +386,7 @@ void dhcprequest (packet, ms_nulltp)
        memset (&data, 0, sizeof data);
        if (oc &&
            evaluate_option_cache (&data, packet, (struct lease *)0,
+                                  (struct client_state *)0,
                                   packet -> options, (struct option_state *)0,
                                   &global_scope, oc, MDL)) {
                cip.len = 4;
@@ -256,7 +405,7 @@ void dhcprequest (packet, ms_nulltp)
        lease = (struct lease *)0;
        if (find_subnet (&subnet, cip, MDL))
                find_lease (&lease, packet,
-                           subnet -> shared_network, &ours, 0, MDL);
+                           subnet -> shared_network, &ours, 0, ip_lease, MDL);
        /* XXX consider using allocatedp arg to find_lease to see
           XXX that this isn't a compliant DHCPREQUEST. */
 
@@ -351,8 +500,8 @@ void dhcprequest (packet, ms_nulltp)
           RENEWING client, so we can punt on this issue. */
 
        if (!packet -> shared_network ||
-           (packet -> raw -> ciaddr.s_addr &&
-            packet -> raw -> giaddr.s_addr) ||
+           (packet -> raw -> ciaddr.s_addr /* &&
+            packet -> raw -> giaddr.s_addr */) ||
            (oc && !packet -> raw -> ciaddr.s_addr)) {
                
                /* If we don't know where it came from but we do know
@@ -436,6 +585,7 @@ void dhcprelease (packet, ms_nulltp)
        memset (&data, 0, sizeof data);
        if (oc &&
            evaluate_option_cache (&data, packet, (struct lease *)0,
+                                  (struct client_state *)0,
                                   packet -> options, (struct option_state *)0,
                                   &global_scope, oc, MDL)) {
                find_lease_by_uid (&lease, data.data, data.len, MDL);
@@ -519,15 +669,15 @@ void dhcpdecline (packet, ms_nulltp)
        int ms_nulltp;
 {
        struct lease *lease = (struct lease *)0;
-       struct iaddr cip;
-       struct option_cache *oc;
-       struct data_string data;
        struct option_state *options = (struct option_state *)0;
        int ignorep = 0;
        int i;
        const char *status;
        char *s;
        char msgbuf [1024]; /* XXX */
+       struct iaddr cip;
+       struct option_cache *oc;
+       struct data_string data;
 
        /* DHCPDECLINE must specify address. */
        if (!(oc = lookup_option (&dhcp_universe, packet -> options,
@@ -535,6 +685,7 @@ void dhcpdecline (packet, ms_nulltp)
                return;
        memset (&data, 0, sizeof data);
        if (!evaluate_option_cache (&data, packet, (struct lease *)0,
+                                   (struct client_state *)0,
                                    packet -> options,
                                    (struct option_state *)0,
                                    &global_scope, oc, MDL))
@@ -572,6 +723,7 @@ void dhcpdecline (packet, ms_nulltp)
        if (lease)
                execute_statements_in_scope ((struct binding_value **)0,
                                             packet, (struct lease *)0,
+                                            (struct client_state *)0,
                                             packet -> options, options,
                                             &global_scope,
                                             lease -> subnet -> group,
@@ -580,8 +732,8 @@ void dhcpdecline (packet, ms_nulltp)
        /* Execute statements in the class scopes. */
        for (i = packet -> class_count; i > 0; i--) {
                execute_statements_in_scope
-                       ((struct binding_value **)0,
-                        packet, (struct lease *)0, packet -> options, options,
+                       ((struct binding_value **)0, packet, (struct lease *)0,
+                        (struct client_state *)0, packet -> options, options,
                         &global_scope, packet -> classes [i - 1] -> group,
                         lease ? lease -> subnet -> group : (struct group *)0);
        }
@@ -590,6 +742,7 @@ void dhcpdecline (packet, ms_nulltp)
        oc = lookup_option (&server_universe, options, SV_DECLINES);
        if (!oc ||
            evaluate_boolean_option_cache (&ignorep, packet, lease,
+                                          (struct client_state *)0,
                                           packet -> options, options,
                                           &lease -> scope, oc, MDL)) {
            /* If we found a lease, mark it as unusable and complain. */
@@ -714,6 +867,7 @@ void dhcpinform (packet, ms_nulltp)
        if (subnet)
                execute_statements_in_scope ((struct binding_value **)0,
                                             packet, (struct lease *)0,
+                                            (struct client_state *)0,
                                             packet -> options, options,
                                             &global_scope, subnet -> group,
                                             (struct group *)0);
@@ -721,8 +875,8 @@ void dhcpinform (packet, ms_nulltp)
        /* Execute statements in the class scopes. */
        for (i = packet -> class_count; i > 0; i--) {
                execute_statements_in_scope
-                       ((struct binding_value **)0,
-                        packet, (struct lease *)0, packet -> options, options,
+                       ((struct binding_value **)0, packet, (struct lease *)0,
+                        (struct client_state *)0, packet -> options, options,
                         &global_scope, packet -> classes [i - 1] -> group,
                         subnet ? subnet -> group : (struct group *)0);
        }
@@ -732,6 +886,7 @@ void dhcpinform (packet, ms_nulltp)
        oc = lookup_option (&server_universe, options, SV_FILENAME);
        if (oc &&
            evaluate_option_cache (&d1, packet, (struct lease *)0,
+                                  (struct client_state *)0,
                                   packet -> options, (struct option_state *)0,
                                   &global_scope, oc, MDL)) {
                i = d1.len;
@@ -746,7 +901,8 @@ void dhcpinform (packet, ms_nulltp)
        /* Choose a server name as above. */
        oc = lookup_option (&server_universe, options, SV_SERVER_NAME);
        if (oc &&
-           evaluate_option_cache (&d1, packet, (struct lease *)0, 
+           evaluate_option_cache (&d1, packet, (struct lease *)0,
+                                  (struct client_state *)0,
                                   packet -> options, (struct option_state *)0,
                                   &global_scope, oc, MDL)) {
                i = d1.len;
@@ -763,7 +919,8 @@ void dhcpinform (packet, ms_nulltp)
        nulltp = 0;
        if ((oc = lookup_option (&dhcp_universe, packet -> options,
                                 DHO_HOST_NAME))) {
-               if (evaluate_option_cache (&d1, packet, (struct lease *)0, 
+               if (evaluate_option_cache (&d1, packet, (struct lease *)0,
+                                          (struct client_state *)0,
                                           packet -> options, options,
                                           &global_scope, oc, MDL)) {
                        if (d1.data [d1.len - 1] == '\0')
@@ -804,6 +961,7 @@ void dhcpinform (packet, ms_nulltp)
                from = packet -> interface -> primary_address;
        } else {
                if (evaluate_option_cache (&d1, packet, (struct lease *)0,
+                                          (struct client_state *)0,
                                           packet -> options, options,
                                           &global_scope, oc, MDL)) {
                        if (!d1.len || d1.len != sizeof from) {
@@ -837,6 +995,7 @@ void dhcpinform (packet, ms_nulltp)
        i = SV_SITE_OPTION_SPACE;
        if ((oc = lookup_option (&server_universe, options, i)) &&
            evaluate_option_cache (&d1, packet, (struct lease *)0,
+                                  (struct client_state *)0,
                                   packet -> options, options,
                                   &global_scope, oc, MDL)) {
                struct universe *u = (struct universe *)0;
@@ -875,6 +1034,7 @@ void dhcpinform (packet, ms_nulltp)
 
        if (oc)
                evaluate_option_cache (&prl, packet, (struct lease *)0,
+                                      (struct client_state *)0,
                                       packet -> options, options,
                                       &global_scope, oc, MDL);
 
@@ -890,6 +1050,7 @@ void dhcpinform (packet, ms_nulltp)
        if ((oc =
             lookup_option (&server_universe, options, SV_NEXT_SERVER))) {
                if (evaluate_option_cache (&d1, packet, (struct lease *)0,
+                                          (struct client_state *)0,
                                           packet -> options, options,
                                           &global_scope, oc, MDL)) {
                        /* If there was more than one answer,
@@ -903,6 +1064,7 @@ void dhcpinform (packet, ms_nulltp)
        /* Set up the option buffer... */
        outgoing.packet_length =
                cons_options (packet, outgoing.raw, (struct lease *)0,
+                             (struct client_state *)0,
                              0, packet -> options, options, &global_scope,
                              0, nulltp, 0,
                              prl.len ? &prl : (struct data_string *)0,
@@ -1034,6 +1196,7 @@ void nak_lease (packet, cip)
        } else {
                memset (&data, 0, sizeof data);
                if (evaluate_option_cache (&data, packet, (struct lease *)0,
+                                          (struct client_state *)0,
                                           packet -> options, options,
                                           &global_scope, oc, MDL)) {
                        if (!data.len ||
@@ -1055,6 +1218,7 @@ void nak_lease (packet, cip)
        /* Set up the option buffer... */
        outgoing.packet_length =
                cons_options (packet, outgoing.raw, (struct lease *)0,
+                             (struct client_state *)0,
                              0, packet -> options, options, &global_scope,
                              0, 0, 0, (struct data_string *)0, (char *)0);
        option_state_dereference (&options, MDL);
@@ -1181,12 +1345,20 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                           packet -> options, DHO_DHCP_SERVER_IDENTIFIER))
                state -> got_server_identifier = 1;
 
-       /* Steal the agent options from the packet. */
-       if (packet -> options -> universes [agent_universe.index]) {
-           option_state_reference
-                   ((struct option_state **)
+       /* If this is not a unicast DHCPREQUEST, steal the agent options
+          from the packet.   Do not do this if the packet looks like
+          it came from a client in the RENEWING state or if it was not
+          relayed (giaddr is not set). */
+       if (!packet -> raw -> ciaddr.s_addr &&
+           packet -> raw -> giaddr.s_addr &&
+           packet -> options -> universe_count > agent_universe.index &&
+           packet -> options -> universes [agent_universe.index] &&
+           (state -> options -> universe_count <= agent_universe.index ||
+            !state -> options -> universes [agent_universe.index])) {
+           option_cache_reference
+                   ((struct option_cache **)
                     &(state -> options -> universes [agent_universe.index]),
-                    (struct option_state *)
+                    (struct option_cache *)
                     packet -> options -> universes [agent_universe.index],
                     MDL);
        }
@@ -1213,7 +1385,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
 
        /* Execute statements in scope starting with the subnet scope. */
        execute_statements_in_scope ((struct binding_value **)0,
-                                    packet, lease,
+                                    packet, lease, (struct client_state *)0,
                                     packet -> options,
                                     state -> options, &lease -> scope,
                                     lease -> subnet -> group,
@@ -1223,6 +1395,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
        if (lease -> pool)
                execute_statements_in_scope ((struct binding_value **)0,
                                             packet, lease,
+                                            (struct client_state *)0,
                                             packet -> options,
                                             state -> options, &lease -> scope,
                                             lease -> pool -> group,
@@ -1232,7 +1405,8 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
        for (i = packet -> class_count; i > 0; i--) {
                execute_statements_in_scope
                        ((struct binding_value **)0,
-                        packet, lease, packet -> options, state -> options,
+                        packet, lease, (struct client_state *)0,
+                        packet -> options, state -> options,
                         &lease -> scope, packet -> classes [i - 1] -> group,
                         (lease -> pool
                          ? lease -> pool -> group
@@ -1243,7 +1417,9 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
           with its group. */
        if (lease -> host)
                execute_statements_in_scope ((struct binding_value **)0,
-                                            packet, lease, packet -> options,
+                                            packet, lease,
+                                            (struct client_state *)0,
+                                            packet -> options,
                                             state -> options, &lease -> scope,
                                             lease -> host -> group,
                                             (lease -> pool
@@ -1263,7 +1439,9 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
            (oc = lookup_option (&server_universe, state -> options,
                                 SV_ONE_LEASE_PER_CLIENT)) &&
            evaluate_boolean_option_cache (&ignorep,
-                                          packet, lease, packet -> options,
+                                          packet, lease,
+                                          (struct client_state *)0,
+                                          packet -> options,
                                           state -> options, &lease -> scope,
                                           oc, MDL)) {
                struct lease *seek;
@@ -1296,6 +1474,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                     (oc = lookup_option (&server_universe, state -> options,
                                          SV_DUPLICATES)) &&
                     !evaluate_boolean_option_cache (&ignorep, packet, lease,
+                                                    (struct client_state *)0,
                                                     packet -> options,
                                                     state -> options,
                                                     &lease -> scope,
@@ -1330,6 +1509,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
            (oc = lookup_option (&server_universe, state -> options,
                                 SV_MIN_SECS))) {
                if (evaluate_option_cache (&d1, packet, lease,
+                                          (struct client_state *)0,
                                           packet -> options, state -> options,
                                           &lease -> scope, oc, MDL)) {
                        if (d1.len && packet -> raw -> secs < d1.data [0]) {
@@ -1358,6 +1538,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                                    DHO_DHCP_CLIENT_IDENTIFIER);
                if (oc &&
                    evaluate_option_cache (&d1, packet, lease,
+                                          (struct client_state *)0,
                                           packet -> options, state -> options,
                                           &lease -> scope, oc, MDL)) {
                        find_hosts_by_uid (&hp, d1.data, d1.len, MDL);
@@ -1388,7 +1569,9 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
            (oc = lookup_option (&server_universe, state -> options,
                                 SV_BOOT_UNKNOWN_CLIENTS)) &&
            !evaluate_boolean_option_cache (&ignorep,
-                                           packet, lease, packet -> options,
+                                           packet, lease,
+                                           (struct client_state *)0,
+                                           packet -> options,
                                            state -> options,
                                            &lease -> scope, oc, MDL)) {
                if (!ignorep)
@@ -1403,7 +1586,9 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
            (oc = lookup_option (&server_universe, state -> options,
                                   SV_ALLOW_BOOTP)) &&
            !evaluate_boolean_option_cache (&ignorep,
-                                           packet, lease, packet -> options,
+                                           packet, lease,
+                                           (struct client_state *)0,
+                                           packet -> options,
                                            state -> options,
                                            &lease -> scope, oc, MDL)) {
                if (!ignorep)
@@ -1418,7 +1603,9 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                            SV_ALLOW_BOOTING);
        if (oc &&
            !evaluate_boolean_option_cache (&ignorep,
-                                           packet, lease, packet -> options,
+                                           packet, lease,
+                                           (struct client_state *)0,
+                                           packet -> options,
                                            state -> options,
                                            &lease -> scope, oc, MDL)) {
                if (!ignorep)
@@ -1472,6 +1659,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
        oc = lookup_option (&server_universe, state -> options, SV_FILENAME);
        if (oc)
                evaluate_option_cache (&state -> filename, packet, lease,
+                                      (struct client_state *)0,
                                       packet -> options, state -> options,
                                       &lease -> scope, oc, MDL);
 
@@ -1480,6 +1668,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                            SV_SERVER_NAME);
        if (oc)
                evaluate_option_cache (&state -> server_name, packet, lease,
+                                      (struct client_state *)0,
                                       packet -> options, state -> options,
                                       &lease -> scope, oc, MDL);
 
@@ -1510,6 +1699,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                if ((oc = lookup_option (&server_universe, state -> options,
                                         SV_DEFAULT_LEASE_TIME))) {
                        if (evaluate_option_cache (&d1, packet, lease,
+                                                  (struct client_state *)0,
                                                   packet -> options,
                                                   state -> options,
                                                   &lease -> scope, oc, MDL)) {
@@ -1523,6 +1713,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                if ((oc = lookup_option (&dhcp_universe, packet -> options,
                                         DHO_DHCP_LEASE_TIME)))
                        s1 = evaluate_option_cache (&d1, packet, lease,
+                                                   (struct client_state *)0,
                                                    packet -> options,
                                                    state -> options,
                                                    &lease -> scope, oc, MDL);
@@ -1542,6 +1733,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                if ((oc = lookup_option (&server_universe, state -> options,
                                         SV_MAX_LEASE_TIME))) {
                        if (evaluate_option_cache (&d1, packet, lease,
+                                                  (struct client_state *)0,
                                                   packet -> options,
                                                   state -> options,
                                                   &lease -> scope, oc, MDL)) {
@@ -1564,6 +1756,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                if ((oc = lookup_option (&server_universe, state -> options,
                                         SV_MIN_LEASE_TIME))) {
                        if (evaluate_option_cache (&d1, packet, lease,
+                                                  (struct client_state *)0,
                                                   packet -> options,
                                                   state -> options,
                                                   &lease -> scope, oc, MDL)) {
@@ -1650,6 +1843,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                if ((oc = lookup_option (&server_universe, state -> options,
                                         SV_BOOTP_LEASE_LENGTH))) {
                        if (evaluate_option_cache (&d1, packet, lease,
+                                                  (struct client_state *)0,
                                                   packet -> options,
                                                   state -> options,
                                                   &lease -> scope, oc, MDL)) {
@@ -1662,6 +1856,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                if ((oc = lookup_option (&server_universe, state -> options,
                                         SV_BOOTP_LEASE_CUTOFF))) {
                        if (evaluate_option_cache (&d1, packet, lease,
+                                                  (struct client_state *)0,
                                                   packet -> options,
                                                   state -> options,
                                                   &lease -> scope, oc, MDL)) {
@@ -1683,6 +1878,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                            DHO_DHCP_CLIENT_IDENTIFIER);
        if (oc &&
            evaluate_option_cache (&d1, packet, lease,
+                                  (struct client_state *)0,
                                   packet -> options, state -> options,
                                   &lease -> scope, oc, MDL)) {
                if (d1.len <= sizeof lt -> uid_buf) {
@@ -1725,10 +1921,39 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                binding_scope_dereference (&lease -> scope, MDL);
        }
 
+       /* If we got relay agent information options, and the packet really
+          looks like it came through a relay agent, and if this feature is
+          not disabled, save the relay agent information options that came
+          in with the packet, so that we can use them at renewal time when
+          the packet won't have gone through a relay agent. */
+       if (!packet -> raw -> ciaddr.s_addr &&
+           packet -> raw -> giaddr.s_addr &&
+           packet -> options -> universe_count > agent_universe.index &&
+           packet -> options -> universes [agent_universe.index] &&
+           (state -> options -> universe_count <= agent_universe.index ||
+            state -> options -> universes [agent_universe.index] ==
+            packet -> options -> universes [agent_universe.index])) {
+           oc = lookup_option (&server_universe, state -> options,
+                               SV_STASH_AGENT_OPTIONS);
+           if (!oc ||
+               evaluate_boolean_option_cache (&ignorep, packet, lease,
+                                              (struct client_state *)0,
+                                              packet -> options,
+                                              state -> options,
+                                              &lease -> scope, oc, MDL)) {
+               option_cache_reference
+                       (&lt -> agent_options,
+                        (struct option_cache *)
+                        packet -> options -> universes [agent_universe.index],
+                        MDL);
+           }
+       }
+
        /* Replace the old lease hostname with the new one, if it's changed. */
        oc = lookup_option (&dhcp_universe, packet -> options, DHO_HOST_NAME);
        if (oc)
                s1 = evaluate_option_cache (&d1, packet, (struct lease *)0,
+                                           (struct client_state *)0,
                                            packet -> options,
                                            (struct option_state *)0,
                                            &global_scope, oc, MDL);
@@ -1755,7 +1980,8 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
           committed, execute them. */
        if (lease -> on_commit && (!offer || offer == DHCPACK)) {
                execute_statements ((struct binding_value **)0,
-                                   packet, lt, packet -> options,
+                                   packet, lt, (struct client_state *)0,
+                                   packet -> options,
                                    state -> options, &lt -> scope,
                                    lease -> on_commit);
                if (lease -> on_commit)
@@ -1813,6 +2039,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
        if ((oc = lookup_option (&server_universe, state -> options,
                                SV_ALWAYS_BROADCAST)) &&
            evaluate_boolean_option_cache (&ignorep, packet, lease,
+                                          (struct client_state *)0,
                                           packet -> options, state -> options,
                                           &lease -> scope, oc, MDL))
                state -> bootp_flags |= htons (BOOTP_BROADCAST);
@@ -1823,6 +2050,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                            DHO_DHCP_MAX_MESSAGE_SIZE);
        if (oc &&
            evaluate_option_cache (&d1, packet, lease,
+                                  (struct client_state *)0,
                                   packet -> options, state -> options,
                                   &lease -> scope, oc, MDL)) {
                if (d1.len == sizeof (u_int16_t))
@@ -1833,6 +2061,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                                    DHO_DHCP_MAX_MESSAGE_SIZE);
                if (oc &&
                    evaluate_option_cache (&d1, packet, lease,
+                                          (struct client_state *)0,
                                           packet -> options, state -> options,
                                           &lease -> scope, oc, MDL)) {
                        if (d1.len == sizeof (u_int16_t))
@@ -1883,6 +2112,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                                state -> from.len);
                } else {
                        if (evaluate_option_cache (&d1, packet, lease,
+                                                  (struct client_state *)0,
                                                   packet -> options,
                                                   state -> options,
                                                   &lease -> scope, oc, MDL)) {
@@ -1974,6 +2204,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
             lookup_option (&server_universe,
                            state -> options, SV_NEXT_SERVER))) {
                if (evaluate_option_cache (&d1, packet, lease,
+                                          (struct client_state *)0,
                                           packet -> options, state -> options,
                                           &lease -> scope, oc, MDL)) {
                        /* If there was more than one answer,
@@ -2010,8 +2241,8 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
        if (!lookup_option (&dhcp_universe, state -> options, i) &&
            lease -> host && lease -> host -> name &&
            (evaluate_boolean_option_cache
-            (&ignorep, packet, lease, packet -> options, state -> options,
-             &lease -> scope,
+            (&ignorep, packet, lease, (struct client_state *)0,
+             packet -> options, state -> options, &lease -> scope,
              lookup_option (&server_universe, state -> options, j), MDL))) {
                oc = (struct option_cache *)0;
                if (option_cache_allocate (&oc, MDL)) {
@@ -2033,9 +2264,9 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
        j = SV_GET_LEASE_HOSTNAMES;
        if (!lookup_option (&server_universe, state -> options, i) &&
            (evaluate_boolean_option_cache
-            (&ignorep, packet, lease, packet -> options, state -> options,
-             &lease -> scope, lookup_option (&server_universe,
-                                               state -> options, j), MDL))) {
+            (&ignorep, packet, lease, (struct client_state *)0,
+             packet -> options, state -> options, &lease -> scope,
+             lookup_option (&server_universe, state -> options, j), MDL))) {
                struct in_addr ia;
                struct hostent *h;
                
@@ -2067,8 +2298,8 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
           so if the local router does proxy arp, you win. */
 
        if (evaluate_boolean_option_cache
-           (&ignorep, packet, lease, packet -> options, state -> options,
-            &lease -> scope,
+           (&ignorep, packet, lease, (struct client_state *)0,
+            packet -> options, state -> options, &lease -> scope,
             lookup_option (&server_universe, state -> options,
                            SV_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE), MDL)) {
                i = DHO_ROUTERS;
@@ -2095,6 +2326,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
        i = SV_SITE_OPTION_SPACE;
        if ((oc = lookup_option (&server_universe, state -> options, i)) &&
            evaluate_option_cache (&d1, packet, lease,
+                                  (struct client_state *)0,
                                   packet -> options, state -> options,
                                   &lease -> scope, oc, MDL)) {
                struct universe *u = (struct universe *)0;
@@ -2127,7 +2359,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                                    DHO_DHCP_PARAMETER_REQUEST_LIST);
        if (oc)
                evaluate_option_cache (&state -> parameter_request_list,
-                                      packet, lease,
+                                      packet, lease, (struct client_state *)0,
                                       packet -> options, state -> options,
                                       &lease -> scope, oc, MDL);
 
@@ -2231,6 +2463,7 @@ void dhcp_reply (lease)
 
        /* Insert such options as will fit into the buffer. */
        packet_length = cons_options (state -> packet, &raw, lease,
+                                     (struct client_state *)0,
                                      state -> max_message_size,
                                      state -> packet -> options,
                                      state -> options, &global_scope,
@@ -2376,7 +2609,8 @@ void dhcp_reply (lease)
 
 int find_lease (struct lease **lp,
                struct packet *packet, struct shared_network *share, int *ours,
-               int *allocatedp, const char *file, int line)
+               int *allocatedp, struct lease *ip_lease_in,
+               const char *file, int line)
 {
        struct lease *uid_lease = (struct lease *)0;
        struct lease *ip_lease = (struct lease *)0;
@@ -2394,23 +2628,27 @@ int find_lease (struct lease **lp,
        int status;
        struct hardware h;
 
-       /* Look up the requested address. */
-       oc = lookup_option (&dhcp_universe, packet -> options,
-                           DHO_DHCP_REQUESTED_ADDRESS);
-       memset (&d1, 0, sizeof d1);
-       if (oc &&
-           evaluate_option_cache (&d1, packet, (struct lease *)0,
-                                  packet -> options, (struct option_state *)0,
-                                  &global_scope, oc, MDL)) {
-               packet -> got_requested_address = 1;
-               cip.len = 4;
-               memcpy (cip.iabuf, d1.data, cip.len);
-               data_string_forget (&d1, MDL);
-       } else if (packet -> raw -> ciaddr.s_addr) {
+       if (packet -> raw -> ciaddr.s_addr) {
                cip.len = 4;
                memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
-       } else
-               cip.len = 0;
+       } else {
+               /* Look up the requested address. */
+               oc = lookup_option (&dhcp_universe, packet -> options,
+                                   DHO_DHCP_REQUESTED_ADDRESS);
+               memset (&d1, 0, sizeof d1);
+               if (oc &&
+                   evaluate_option_cache (&d1, packet, (struct lease *)0,
+                                          (struct client_state *)0,
+                                          packet -> options,
+                                          (struct option_state *)0,
+                                          &global_scope, oc, MDL)) {
+                       packet -> got_requested_address = 1;
+                       cip.len = 4;
+                       memcpy (cip.iabuf, d1.data, cip.len);
+                       data_string_forget (&d1, MDL);
+               } else 
+                       cip.len = 0;
+       }
 
        /* Try to find a host or lease that's been assigned to the
           specified unique client identifier. */
@@ -2420,6 +2658,7 @@ int find_lease (struct lease **lp,
        if (oc &&
            evaluate_option_cache (&client_identifier,
                                   packet, (struct lease *)0,
+                                  (struct client_state *)0,
                                   packet -> options, (struct option_state *)0,
                                   &global_scope, oc, MDL)) {
                /* Remember this for later. */
@@ -2594,7 +2833,9 @@ int find_lease (struct lease **lp,
 
        /* Try to find a lease that's been allocated to the client's
           IP address. */
-       if (cip.len)
+       if (ip_lease_in)
+               lease_reference (&ip_lease, ip_lease_in, MDL);
+       else if (cip.len)
                find_lease_by_ip_addr (&ip_lease, cip, MDL);
 
 #if defined (DEBUG_FIND_LEASE)
@@ -2722,6 +2963,13 @@ int find_lease (struct lease **lp,
                        strcpy (dhcp_message,
                                "database conflict - call for help!");
                }
+
+               if (ip_lease && ip_lease != uid_lease) {
+#if defined (DEBUG_FIND_LEASE)
+                       log_info ("requested address not available.");
+#endif
+                       lease_dereference (&ip_lease, MDL);
+               }
        }
 
        /* If we get to here with both fixed_lease and ip_lease not
@@ -2999,6 +3247,8 @@ void static_lease_dereference (lease, file, line)
                                                  file, line);
        if (lease -> scope)
                binding_scope_dereference (&lease -> scope, file, line);
+       if (lease -> agent_options)
+               option_cache_dereference (&lease -> agent_options, file, line);
        if (lease -> uid != lease -> uid_buf) {
                dfree (lease -> uid, file, line);
                lease -> uid = (unsigned char *)0;
@@ -3196,6 +3446,7 @@ int locate_network (packet)
        if (oc) {
                memset (&data, 0, sizeof data);
                if (!evaluate_option_cache (&data, packet, (struct lease *)0,
+                                           (struct client_state *)0,
                                            packet -> options,
                                            (struct option_state *)0,
                                            &global_scope, oc, MDL)) {
index 153eb692a10348ea9362b8f3106f6e841ac91bb6..80c5033147c46a58adbc765e9710c8dd06dfb28f 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char ocopyright[] =
-"$Id: dhcpd.c,v 1.101 2000/09/01 23:06:31 mellon Exp $ Copyright 1995-2000 Internet Software Consortium.";
+"$Id: dhcpd.c,v 1.102 2000/11/28 23:27:19 mellon Exp $ Copyright 1995-2000 Internet Software Consortium.";
 #endif
 
   static char copyright[] =
@@ -71,62 +71,75 @@ int server_identifier_matched;
 char std_nsupdate [] = "                                                   \n\
 on commit {                                                                \n\
   if (((config-option server.ddns-updates = null) or                       \n\
-       (config-option server.ddns-updates != 0)) and                       \n\
-      (not defined (ddns-fwd-name))) {                                     \n\
-    set ddns-fwd-name = concat (pick (config-option server.ddns-hostname,   \n\
-                                     option host-name), \".\",             \n\
-                               pick (config-option server.ddns-domainname, \n\
-                                     config-option domain-name));          \n\
-    if defined (ddns-fwd-name) {                                           \n\
-      switch (ns-update (not exists (IN, A, ddns-fwd-name, null),          \n\
-                        add (IN, A, ddns-fwd-name, leased-address,         \n\
-                             lease-time / 2))) {                           \n\
-       default:                                                                    \n\
-        unset ddns-fwd-name;                                               \n\
-        break;                                                             \n\
+       (config-option server.ddns-updates != 0))) {                        \n\
+    set new-ddns-fwd-name =                                                \n\
+      concat (pick (config-option server.ddns-hostname,                            \n\
+                   option host-name), \".\",                               \n\
+             pick (config-option server.ddns-domainname,                   \n\
+                   config-option domain-name));                            \n\
+    if (defined (ddns-fwd-name) and ddns-fwd-name != new-ddns-fwd-name) {   \n\
+      switch (ns-update (delete (IN, A, ddns-fwd-name, leased-address))) {  \n\
+      case NOERROR:                                                        \n\
+       unset ddns-fwd-name;                                                \n\
+       on expiry or release {                                              \n\
+       }
+      }                                                                            \n\
+    }                                                                      \n\
                                                                            \n\
-       case NOERROR:                                                       \n\
-        set ddns-rev-name =                                                \n\
-               concat (binary-to-ascii (10, 8, \".\",                      \n\
-                                        reverse (1,                        \n\
-                                                 leased-address)), \".\",  \n\
-                       pick (config-option server.ddns-rev-domainname,     \n\
-                             \"in-addr.arpa.\"));                          \n\
-        switch (ns-update (delete (IN, PTR, ddns-rev-name, null),          \n\
-                          add (IN, PTR, ddns-rev-name, ddns-fwd-name,      \n\
-                               lease-time / 2)))                           \n\
-       {                                                                   \n\
-         default:                                                          \n\
-         unset ddns-rev-name;                                              \n\
-         on release or expiry {                                            \n\
-           switch (ns-update (delete (IN, A, ddns-fwd-name,                \n\
-                                      leased-address))) {                  \n\
-             case NOERROR:                                                 \n\
-               unset ddns-fwd-name;                                        \n\
-               break;                                                      \n\
-           }                                                               \n\
-           on release or expiry;                                           \n\
-          }                                                                \n\
+    if (not defined (ddns-fwd-name)) {                                     \n\
+      set ddns-fwd-name = new-ddns-fwd-name;                               \n\
+      if defined (ddns-fwd-name) {                                         \n\
+       switch (ns-update (not exists (IN, A, ddns-fwd-name, null),         \n\
+                          add (IN, A, ddns-fwd-name, leased-address,       \n\
+                               lease-time / 2))) {                         \n\
+       default:                                                            \n\
+         unset ddns-fwd-name;                                              \n\
          break;                                                            \n\
                                                                            \n\
-         case NOERROR:                                                     \n\
-         on release or expiry {                                            \n\
-           switch (ns-update (delete (IN, PTR, ddns-rev-name, null))) {    \n\
-             case NOERROR:                                                 \n\
-               unset ddns-rev-name;                                        \n\
-               break;                                                      \n\
-           }                                                               \n\
-           switch (ns-update (delete (IN, A, ddns-fwd-name,                \n\
-                                      leased-address))) {                  \n\
-             case NOERROR:                                                 \n\
-               unset ddns-fwd-name;                                        \n\
-               break;                                                      \n\
+       case NOERROR:                                                       \n\
+         set ddns-rev-name =                                               \n\
+           concat (binary-to-ascii (10, 8, \".\",                          \n\
+                                    reverse (1,                            \n\
+                                             leased-address)), \".\",      \n\
+                   pick (config-option server.ddns-rev-domainname,         \n\
+                         \"in-addr.arpa.\"));                              \n\
+         switch (ns-update (delete (IN, PTR, ddns-rev-name, null),         \n\
+                            add (IN, PTR, ddns-rev-name, ddns-fwd-name,    \n\
+                                 lease-time / 2)))                         \n\
+           {                                                               \n\
+           default:                                                        \n\
+             unset ddns-rev-name;                                          \n\
+             on release or expiry {                                        \n\
+               switch (ns-update (delete (IN, A, ddns-fwd-name,            \n\
+                                          leased-address))) {              \n\
+               case NOERROR:                                               \n\
+                 unset ddns-fwd-name;                                      \n\
+                 break;                                                    \n\
+               }                                                           \n\
+               on release or expiry;                                       \n\
+             }                                                             \n\
+             break;                                                        \n\
+                                                                           \n\
+           case NOERROR:                                                   \n\
+             on release or expiry {                                        \n\
+               switch (ns-update (delete (IN, PTR, ddns-rev-name, null))) {\n\
+               case NOERROR:                                               \n\
+                 unset ddns-rev-name;                                      \n\
+                 break;                                                    \n\
+               }                                                           \n\
+               switch (ns-update (delete (IN, A, ddns-fwd-name,            \n\
+                                          leased-address))) {              \n\
+               case NOERROR:                                               \n\
+                 unset ddns-fwd-name;                                      \n\
+                 break;                                                    \n\
+               }                                                           \n\
+               on release or expiry;                                       \n\
+             }                                                             \n\
            }                                                               \n\
-           on release or expiry;                                           \n\
-         }                                                                 \n\
-        }                                                                  \n\
+       }                                                                   \n\
       }                                                                            \n\
     }                                                                      \n\
+    unset new-ddns-fwd-name;                                               \n\
   }                                                                        \n\
 }";
 #endif /* NSUPDATE */
@@ -380,6 +393,7 @@ int main (argc, argv, envp)
        execute_statements_in_scope ((struct binding_value **)0,
                                     (struct packet *)0,
                                     (struct lease *)0,
+                                    (struct client_state *)0,
                                     (struct option_state *)0,
                                     options, &global_scope,
                                     root_group,
@@ -388,8 +402,8 @@ int main (argc, argv, envp)
        oc = lookup_option (&server_universe, options, SV_LEASE_FILE_NAME);
        if (oc &&
            evaluate_option_cache (&db, (struct packet *)0,
-                                  (struct lease *)0, options,
-                                  (struct option_state *)0,
+                                  (struct lease *)0, (struct client_state *)0,
+                                  options, (struct option_state *)0,
                                   &global_scope, oc, MDL)) {
                s = dmalloc (db.len + 1, MDL);
                if (!s)
@@ -403,8 +417,8 @@ int main (argc, argv, envp)
        oc = lookup_option (&server_universe, options, SV_PID_FILE_NAME);
        if (oc &&
            evaluate_option_cache (&db, (struct packet *)0,
-                                  (struct lease *)0, options,
-                                  (struct option_state *)0,
+                                  (struct lease *)0, (struct client_state *)0,
+                                  options, (struct option_state *)0,
                                   &global_scope, oc, MDL)) {
                s = dmalloc (db.len + 1, MDL);
                if (!s)
@@ -419,8 +433,8 @@ int main (argc, argv, envp)
        oc = lookup_option (&server_universe, options, SV_OMAPI_PORT);
        if (oc &&
            evaluate_option_cache (&db, (struct packet *)0,
-                                  (struct lease *)0, options,
-                                  (struct option_state *)0,
+                                  (struct lease *)0, (struct client_state *)0,
+                                  options, (struct option_state *)0,
                                   &global_scope, oc, MDL)) {
                if (db.len == 2) {
                        omapi_port = getUShort (db.data);
@@ -432,7 +446,8 @@ int main (argc, argv, envp)
        oc = lookup_option (&server_universe, options, SV_OMAPI_KEY);
        if (oc &&
            evaluate_option_cache (&db, (struct packet *)0,
-                                  (struct lease *)0, options,
+                                  (struct lease *)0, (struct client_state *)0,
+                                  options,
                                   (struct option_state *)0,
                                   &global_scope, oc, MDL)) {
                s = dmalloc (db.len + 1, MDL);
@@ -450,7 +465,8 @@ int main (argc, argv, envp)
        oc = lookup_option (&server_universe, options, SV_LOCAL_PORT);
        if (oc &&
            evaluate_option_cache (&db, (struct packet *)0,
-                                  (struct lease *)0, options,
+                                  (struct lease *)0, (struct client_state *)0,
+                                  options,
                                   (struct option_state *)0,
                                   &global_scope, oc, MDL)) {
                if (db.len == 2) {
@@ -463,8 +479,8 @@ int main (argc, argv, envp)
        oc = lookup_option (&server_universe, options, SV_REMOTE_PORT);
        if (oc &&
            evaluate_option_cache (&db, (struct packet *)0,
-                                  (struct lease *)0, options,
-                                  (struct option_state *)0,
+                                  (struct lease *)0, (struct client_state *)0,
+                                  options, (struct option_state *)0,
                                   &global_scope, oc, MDL)) {
                if (db.len == 2) {
                        remote_port = htons (getUShort (db.data));
@@ -477,8 +493,8 @@ int main (argc, argv, envp)
                            SV_LIMITED_BROADCAST_ADDRESS);
        if (oc &&
            evaluate_option_cache (&db, (struct packet *)0,
-                                  (struct lease *)0, options,
-                                  (struct option_state *)0,
+                                  (struct lease *)0, (struct client_state *)0,
+                                  options, (struct option_state *)0,
                                   &global_scope, oc, MDL)) {
                if (db.len == 4) {
                        memcpy (&limited_broadcast, db.data, 4);
@@ -491,8 +507,8 @@ int main (argc, argv, envp)
                            SV_LOCAL_ADDRESS);
        if (oc &&
            evaluate_option_cache (&db, (struct packet *)0,
-                                  (struct lease *)0, options,
-                                  (struct option_state *)0,
+                                  (struct lease *)0, (struct client_state *)0,
+                                  options, (struct option_state *)0,
                                   &global_scope, oc, MDL)) {
                if (db.len == 4) {
                        memcpy (&local_address, db.data, 4);
index f3d44a70a4342ddde83a4a4b99b0cdf5dbafc8e8..6e7e7c106929378beb5103bb3af73a94897554ce 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: failover.c,v 1.29 2000/11/24 04:19:05 mellon Exp $ Copyright (c) 1999-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: failover.c,v 1.30 2000/11/28 23:27:20 mellon Exp $ Copyright (c) 1999-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -190,6 +190,7 @@ isc_result_t dhcp_failover_link_initiate (omapi_object_t *h)
 
        memset (&ds, 0, sizeof ds);
        if (!evaluate_option_cache (&ds, (struct packet *)0, (struct lease *)0,
+                                   (struct client_state *)0,
                                    (struct option_state *)0,
                                    (struct option_state *)0,
                                    &global_scope, obj -> peer_address, MDL)) {
@@ -218,6 +219,7 @@ isc_result_t dhcp_failover_link_initiate (omapi_object_t *h)
        if (!state -> me.address ||
            !evaluate_option_cache (&ds, (struct packet *)0,
                                    (struct lease *)0,
+                                   (struct client_state *)0,
                                    (struct option_state *)0,
                                    (struct option_state *)0,
                                    &global_scope, state -> me.address,
@@ -2248,6 +2250,7 @@ isc_result_t dhcp_failover_state_get_value (omapi_object_t *h,
                memset (&ds, 0, sizeof ds);
                if (!evaluate_option_cache (&ds, (struct packet *)0,
                                            (struct lease *)0,
+                                           (struct client_state *)0,
                                            (struct option_state *)0,
                                            (struct option_state *)0,
                                            &global_scope, oc, MDL)) {
@@ -2645,6 +2648,7 @@ int dhcp_failover_state_match (dhcp_failover_state_t *state,
        memset (&ds, 0, sizeof ds);
        if (evaluate_option_cache (&ds, (struct packet *)0,
                                   (struct lease *)0,
+                                  (struct client_state *)0,
                                   (struct option_state *)0,
                                   (struct option_state *)0,
                                   &global_scope,
@@ -4293,6 +4297,7 @@ int load_balance_mine (struct packet *packet, dhcp_failover_state_t *state)
        memset (&ds, 0, sizeof ds);
        if (oc &&
            evaluate_option_cache (&ds, packet, (struct lease *)0,
+                                  (struct client_state *)0,
                                   packet -> options, (struct option_state *)0,
                                   &global_scope, oc, MDL)) {
                hbaix = loadb_p_hash (ds.data, ds.len);
index ce40563f8e74741cd600bfb0f9dda3f7c40e5295..4d095307b0868a741c533d311b4799d5b4b762ee 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: mdb.c,v 1.43 2000/09/29 18:21:33 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: mdb.c,v 1.44 2000/11/28 23:27:21 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -154,7 +154,8 @@ isc_result_t enter_host (hd, dynamicp, commit)
                     DHO_DHCP_CLIENT_IDENTIFIER)) {
                        evaluate_option_cache
                                (&hd -> client_identifier, (struct packet *)0,
-                                (struct lease *)0, (struct option_state *)0,
+                                (struct lease *)0, (struct client_state *)0,
+                                (struct option_state *)0,
                                 (struct option_state *)0, &global_scope,
                                 esp -> data.option, MDL);
                        break;
@@ -377,6 +378,7 @@ int find_host_for_network (struct subnet **sp, struct host_decl **host,
                        continue;
                if (!evaluate_option_cache (&fixed_addr, (struct packet *)0,
                                            (struct lease *)0,
+                                           (struct client_state *)0,
                                            (struct option_state *)0,
                                            (struct option_state *)0,
                                            &global_scope,
@@ -875,6 +877,21 @@ int supersede_lease (comp, lease, commit, propogate, pimmediate)
                binding_scope_dereference (&lease -> scope, MDL);
        }
 
+       if (comp -> agent_options)
+               option_cache_dereference (&comp -> agent_options, MDL);
+       if (lease -> agent_options) {
+               /* Only retain the agent options if the lease is still
+                  affirmatively associated with a client. */
+               if (lease -> binding_state == FTS_ACTIVE ||
+                   lease -> binding_state == FTS_EXPIRED ||
+                   lease -> binding_state == FTS_ABANDONED ||
+                   lease -> binding_state == FTS_RESERVED ||
+                   lease -> binding_state == FTS_BOOTP)
+                       option_cache_reference (&comp -> agent_options,
+                                               lease -> agent_options, MDL);
+               option_cache_dereference (&lease -> agent_options, MDL);
+       }
+
        /* Record the hostname information in the lease. */
        if (comp -> hostname)
                dfree (comp -> hostname, MDL);
@@ -1048,6 +1065,7 @@ void process_state_transition (struct lease *lease)
                if (lease -> on_expiry) {
                        execute_statements ((struct binding_value **)0,
                                            (struct packet *)0, lease,
+                                           (struct client_state *)0,
                                            (struct option_state *)0,
                                            (struct option_state *)0, /* XXX */
                                            &lease -> scope,
@@ -1074,6 +1092,7 @@ void process_state_transition (struct lease *lease)
                if (lease -> on_release) {
                        execute_statements ((struct binding_value **)0,
                                            (struct packet *)0, lease,
+                                           (struct client_state *)0,
                                            (struct option_state *)0,
                                            (struct option_state *)0, /* XXX */
                                            &lease -> scope,
@@ -1152,6 +1171,9 @@ int lease_copy (struct lease **lp,
        }
        if (lease -> scope)
                binding_scope_reference (&lt -> scope, lease -> scope, MDL);
+       if (lease -> agent_options)
+               option_cache_reference (&lt -> agent_options,
+                                       lease -> agent_options, MDL);
        host_reference (&lt -> host, lease -> host, file, line);
        subnet_reference (&lt -> subnet, lease -> subnet, file, line);
        pool_reference (&lt -> pool, lease -> pool, file, line);
@@ -1190,7 +1212,8 @@ void release_lease (lease, packet)
           released, execute them. */
        if (lease -> on_release) {
                execute_statements ((struct binding_value **)0,
-                                   packet, lease, packet -> options,
+                                   packet, lease, (struct client_state *)0,
+                                   packet -> options,
                                    (struct option_state *)0, /* XXX */
                                    &lease -> scope, lease -> on_release);
                if (lease -> on_release)
index 557f97ad8a847ed1968661be9c3cbc8e7aeb2ef2..4d227c87d071bb2d1153fea8e1c4b41e561eea60 100644 (file)
@@ -50,7 +50,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: omapi.c,v 1.40 2000/10/20 01:01:41 neild Exp $ Copyright (c) 1999-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: omapi.c,v 1.41 2000/11/28 23:27:22 mellon Exp $ Copyright (c) 1999-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -934,6 +934,7 @@ isc_result_t dhcp_host_get_value (omapi_object_t *h, omapi_object_t *id,
            if (host -> fixed_addr &&
                evaluate_option_cache (&ip_addrs, (struct packet *)0,
                                       (struct lease *)0,
+                                      (struct client_state *)0,
                                       (struct option_state *)0,
                                       (struct option_state *)0,
                                       &global_scope,
@@ -1067,6 +1068,7 @@ isc_result_t dhcp_host_stuff_values (omapi_object_t *c,
        if (host -> fixed_addr &&
            evaluate_option_cache (&ip_addrs, (struct packet *)0,
                                   (struct lease *)0,
+                                  (struct client_state *)0,
                                   (struct option_state *)0,
                                   (struct option_state *)0,
                                   &global_scope,
index 8b0031372a6a515ccafc719183b0d42ceceeccfa..4d8f894b1a748c3341ab63cce090f54dae885597 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: stables.c,v 1.18 2000/10/10 23:09:17 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: stables.c,v 1.19 2000/11/28 23:27:24 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -482,7 +482,7 @@ struct option server_options [256] = {
        { "remote-port", "S",                   &server_universe, 34 },
        { "local-address", "I",                 &server_universe, 35 },
        { "omapi-key", "t",                     &server_universe, 36 },
-       { "option-37", "X",                     &server_universe, 37 },
+       { "stash-agent-options", "f",           &server_universe, 37 },
        { "option-38", "X",                     &server_universe, 38 },
        { "option-39", "X",                     &server_universe, 39 },
        { "option-40", "X",                     &server_universe, 40 },