]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
OMAPI interface for ISC DHCP server objects.
authorTed Lemon <source@isc.org>
Wed, 8 Sep 1999 01:36:05 +0000 (01:36 +0000)
committerTed Lemon <source@isc.org>
Wed, 8 Sep 1999 01:36:05 +0000 (01:36 +0000)
server/omapi.c [new file with mode: 0644]

diff --git a/server/omapi.c b/server/omapi.c
new file mode 100644 (file)
index 0000000..4ae3801
--- /dev/null
@@ -0,0 +1,1147 @@
+/* omapi.c
+
+   OMAPI object interfaces for the DHCP server. */
+
+/*
+ * Copyright (c) 1996-1999 Internet Software Consortium.
+ * Use is subject to license terms which appear in the file named
+ * ISC-LICENSE that should have accompanied this file when you
+ * received it.   If a file named ISC-LICENSE did not accompany this
+ * file, or you are not sure the one you have is correct, you may
+ * obtain an applicable copy of the license at:
+ *
+ *             http://www.isc.org/isc-license-1.0.html. 
+ *
+ * This file is part of the ISC DHCP distribution.   The documentation
+ * associated with this file is listed in the file DOCUMENTATION,
+ * included in the top-level directory of this release.
+ *
+ * Support and other services are available for ISC products - see
+ * http://www.isc.org for more information.
+ */
+
+/* Many, many thanks to Brian Murrell and BCtel for this code - BCtel
+   provided the funding that resulted in this code and the entire
+   OMAPI support library being written, and Brian helped brainstorm
+   and refine the requirements.  To the extent that this code is
+   useful, you have Brian and BCtel to thank.  Any limitations in the
+   code are a result of mistakes on my part.  -- Ted Lemon */
+
+#ifndef lint
+static char copyright[] =
+"$Id: omapi.c,v 1.1 1999/09/08 01:36:05 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+
+omapi_object_type_t *dhcp_type_lease;
+omapi_object_type_t *dhcp_type_group;
+omapi_object_type_t *dhcp_type_host;
+omapi_object_type_t *dhcp_type_pool;
+omapi_object_type_t *dhcp_type_shared_network;
+omapi_object_type_t *dhcp_type_subnet;
+omapi_object_type_t *dhcp_type_class;
+
+void dhcp_db_objects_setup ()
+{
+       isc_result_t status;
+
+       status = omapi_object_type_register (&dhcp_type_lease,
+                                            "lease",
+                                            dhcp_lease_set_value,
+                                            dhcp_lease_get_value,
+                                            dhcp_lease_destroy,
+                                            dhcp_lease_signal_handler,
+                                            dhcp_lease_stuff_values,
+                                            dhcp_lease_lookup, 
+                                            dhcp_lease_create);
+       if (status != ISC_R_SUCCESS)
+               log_fatal ("Can't register lease object type: %s",
+                          isc_result_totext (status));
+
+       status = omapi_object_type_register (&dhcp_type_host,
+                                            "host",
+                                            dhcp_host_set_value,
+                                            dhcp_host_get_value,
+                                            dhcp_host_destroy,
+                                            dhcp_host_signal_handler,
+                                            dhcp_host_stuff_values,
+                                            dhcp_host_lookup, 
+                                            dhcp_host_create);
+       if (status != ISC_R_SUCCESS)
+               log_fatal ("Can't register host object type: %s",
+                          isc_result_totext (status));
+
+       status = omapi_object_type_register (&dhcp_type_pool,
+                                            "pool",
+                                            dhcp_pool_set_value,
+                                            dhcp_pool_get_value,
+                                            dhcp_pool_destroy,
+                                            dhcp_pool_signal_handler,
+                                            dhcp_pool_stuff_values,
+                                            dhcp_pool_lookup, 
+                                            dhcp_pool_create);
+       if (status != ISC_R_SUCCESS)
+               log_fatal ("Can't register pool object type: %s",
+                          isc_result_totext (status));
+}
+
+isc_result_t dhcp_lease_set_value  (omapi_object_t *h,
+                                   omapi_object_t *id,
+                                   omapi_data_string_t *name,
+                                   omapi_typed_data_t *value)
+{
+       struct lease *lease;
+       isc_result_t status;
+       int foo;
+
+       if (h -> type != omapi_type_message)
+               return ISC_R_INVALIDARG;
+       lease = (struct lease *)h;
+
+       /* We're skipping a lot of things it might be interesting to
+          set - for now, we just make it possible to whack the abandoned
+          flag. */
+       if (!omapi_ds_strcmp (name, "abandoned")) {
+               int bar;
+
+               if (value -> type == omapi_datatype_int)
+                       bar = value -> u.integer;
+               else if (value -> type == omapi_datatype_data &&
+                        value -> u.buffer.len == sizeof (int)) {
+                       memcpy (&bar, value -> u.buffer.value, sizeof bar);
+                       /* No need to byte-swap here. */
+               } else
+                       return ISC_R_INVALIDARG;
+
+               foo = lease -> flags;
+               if (bar)
+                       lease -> flags |= ABANDONED_LEASE;
+               else
+                       lease -> flags &= ~ABANDONED_LEASE;
+               if (foo != lease -> flags)
+                       return ISC_R_SUCCESS;
+               return ISC_R_UNCHANGED;
+       }
+
+       /* Try to find some inner object that can take the value. */
+       if (h -> inner && h -> inner -> type -> set_value) {
+               status = ((*(h -> inner -> type -> set_value))
+                         (h -> inner, id, name, value));
+               if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED)
+                       return status;
+       }
+                         
+       return ISC_R_NOTFOUND;
+}
+
+
+isc_result_t dhcp_lease_get_value (omapi_object_t *h, omapi_object_t *id,
+                                  omapi_data_string_t *name,
+                                  omapi_value_t **value)
+{
+       struct lease *lease;
+       isc_result_t status;
+
+       if (h -> type != dhcp_type_lease)
+               return ISC_R_INVALIDARG;
+       lease = (struct lease *)h;
+
+       if (!omapi_ds_strcmp (name, "abandoned"))
+               return omapi_make_int_value (value, name,
+                                            (lease -> flags &
+                                             ABANDONED_LEASE) ? 1 : 0,
+                                            "dhcp_lease_get_value");
+       else if (!omapi_ds_strcmp (name, "bootpp"))
+               return omapi_make_int_value (value, name,
+                                            (lease -> flags &
+                                             BOOTP_LEASE) ? 1 : 0,
+                                            "dhcp_lease_get_value");
+       else if (!omapi_ds_strcmp (name, "ip-address"))
+               return omapi_make_const_value (value, name,
+                                              lease -> ip_addr.iabuf,
+                                              lease -> ip_addr.len,
+                                              "dhcp_lease_get_value");
+       else if (!omapi_ds_strcmp (name, "dhcp-client-identifier"))
+               return omapi_make_const_value (value, name,
+                                              lease -> uid,
+                                              lease -> uid_len,
+                                              "dhcp_lease_get_value");
+       else if (!omapi_ds_strcmp (name, "hostname"))
+               return omapi_make_string_value (value, name,
+                                               lease -> hostname,
+                                               "dhcp_lease_get_value");
+       else if (!omapi_ds_strcmp (name, "client-hostname"))
+               return omapi_make_string_value (value, name,
+                                               lease -> client_hostname,
+                                               "dhcp_lease_get_value");
+       else if (!omapi_ds_strcmp (name, "ddns-fwd-name"))
+               return omapi_make_string_value (value, name,
+                                               lease -> ddns_fwd_name,
+                                               "dhcp_lease_get_value");
+       else if (!omapi_ds_strcmp (name, "ddns-rev-name"))
+               return omapi_make_string_value (value, name,
+                                               lease -> ddns_rev_name,
+                                               "dhcp_lease_get_value");
+       else if (!omapi_ds_strcmp (name, "host"))
+               return omapi_make_handle_value (value, name,
+                                               ((omapi_object_t *)
+                                                lease -> host),
+                                               "dhcp_lease_get_value");
+       else if (!omapi_ds_strcmp (name, "subnet"))
+               return omapi_make_handle_value (value, name,
+                                               ((omapi_object_t *)
+                                                lease -> subnet),
+                                               "dhcp_lease_get_value");
+       else if (!omapi_ds_strcmp (name, "pool"))
+               return omapi_make_handle_value (value, name,
+                                               ((omapi_object_t *)
+                                                lease -> pool),
+                                               "dhcp_lease_get_value");
+       else if (!omapi_ds_strcmp (name, "billing-class"))
+               return omapi_make_handle_value (value, name,
+                                               ((omapi_object_t *)
+                                                lease -> billing_class),
+                                               "dhcp_lease_get_value");
+       else if (!omapi_ds_strcmp (name, "hardware-address"))
+               return omapi_make_const_value (value, name,
+                                              lease -> hardware_addr.haddr,
+                                              lease -> hardware_addr.hlen,
+                                              "dhcp_lease_get_value");
+       else if (!omapi_ds_strcmp (name, "hardware-type"))
+               return omapi_make_int_value (value, name,
+                                            lease -> hardware_addr.htype,
+                                            "dhcp_lease_get_value");
+
+       /* Try to find some inner object that can take the value. */
+       if (h -> inner && h -> inner -> type -> get_value) {
+               status = ((*(h -> inner -> type -> get_value))
+                         (h -> inner, id, name, value));
+               if (status == ISC_R_SUCCESS)
+                       return status;
+       }
+       return ISC_R_NOTFOUND;
+}
+
+isc_result_t dhcp_lease_destroy (omapi_object_t *h, char *name)
+{
+       struct lease *lease;
+       isc_result_t status;
+
+       if (h -> type != dhcp_type_lease)
+               return ISC_R_INVALIDARG;
+       lease = (struct lease *)h;
+
+       uid_hash_delete (lease);
+       hw_hash_delete (lease);
+       if (lease -> billing_class)
+               omapi_object_dereference
+                       ((omapi_object_t **)&lease -> billing_class, name);
+       if (lease -> uid && lease -> uid != &lease -> uid_buf [0]) {
+               free (lease -> uid);
+               lease -> uid = &lease -> uid_buf [0];
+               lease -> uid_len = 0;
+       }
+       if (lease -> hostname) {
+               free (lease -> hostname);
+               lease -> hostname = (char *)0;
+       }
+       if (lease -> client_hostname) {
+               free (lease -> client_hostname);
+               lease -> hostname = (char *)0;
+       }
+       if (lease -> ddns_fwd_name) {
+               free (lease -> ddns_fwd_name);
+               lease -> ddns_fwd_name = (char *)0;
+       }
+       if (lease -> ddns_rev_name) {
+               free (lease -> ddns_rev_name);
+               lease -> ddns_rev_name = (char *)0;
+       }
+       if (lease -> host)
+               omapi_object_dereference ((omapi_object_t **)&lease -> host,
+                                         name);
+       if (lease -> subnet)
+               omapi_object_dereference ((omapi_object_t **)&lease -> subnet,
+                                         name);
+       if (lease -> pool)
+               omapi_object_dereference ((omapi_object_t **)&lease -> pool,
+                                         name);
+       if (lease -> on_expiry)
+               executable_statement_dereference (&lease -> on_expiry, name);
+       if (lease -> on_commit)
+               executable_statement_dereference (&lease -> on_commit, name);
+       if (lease -> on_release)
+               executable_statement_dereference (&lease -> on_release, name);
+       if (lease -> state) {
+               data_string_forget (&lease -> state -> parameter_request_list,
+                                   name);
+               free_lease_state (lease -> state, name);
+               lease -> state = (struct lease_state *)0;
+
+               cancel_timeout (lease_ping_timeout, lease);
+               --outstanding_pings; /* XXX */
+       }
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_lease_signal_handler (omapi_object_t *h,
+                                       char *name, va_list ap)
+{
+       struct lease *lease;
+       isc_result_t status;
+
+       if (h -> type != dhcp_type_lease)
+               return ISC_R_INVALIDARG;
+       lease = (struct lease *)h;
+
+       if (!strcmp (name, "updated")) {
+               if (!write_lease (lease))
+                       return ISC_R_IOERROR;
+       }
+
+       /* Try to find some inner object that can take the value. */
+       if (h -> inner && h -> inner -> type -> get_value) {
+               status = ((*(h -> inner -> type -> signal_handler))
+                         (h -> inner, name, ap));
+               if (status == ISC_R_SUCCESS)
+                       return status;
+       }
+       return ISC_R_NOTFOUND;
+}
+
+isc_result_t dhcp_lease_stuff_values (omapi_object_t *c,
+                                     omapi_object_t *id,
+                                     omapi_object_t *h)
+{
+       struct lease *lease;
+       isc_result_t status;
+
+       if (h -> type != dhcp_type_lease)
+               return ISC_R_INVALIDARG;
+       lease = (struct lease *)h;
+
+       /* Write out all the values. */
+
+       status = omapi_connection_put_name (c, "abandoned");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_uint32 (c, sizeof (int));
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_uint32 (c, (lease -> flags &
+                                                 ABANDONED_LEASE) ? 1 : 0);
+       if (status != ISC_R_SUCCESS)
+               return status;
+
+       status = omapi_connection_put_name (c, "bootpp");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_uint32 (c, sizeof (int));
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_uint32 (c, (lease -> flags &
+                                                 BOOTP_LEASE) ? 1 : 0);
+       if (status != ISC_R_SUCCESS)
+               return status;
+
+       status = omapi_connection_put_name (c, "ip-address");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_uint32 (c, lease -> ip_addr.len);
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_copyin (c, lease -> ip_addr.iabuf,
+                                         lease -> ip_addr.len);
+       if (status != ISC_R_SUCCESS)
+               return status;
+
+       status = omapi_connection_put_name (c, "dhcp-client-identifier");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_uint32 (c, lease -> uid_len);
+       if (status != ISC_R_SUCCESS)
+               return status;
+       if (lease -> uid_len) {
+               status = omapi_connection_copyin (c, lease -> uid,
+                                                 lease -> uid_len);
+               if (status != ISC_R_SUCCESS)
+                       return status;
+       }
+
+       status = omapi_connection_put_name (c, "hostname");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_string (c, lease -> hostname);
+       if (status != ISC_R_SUCCESS)
+               return status;
+
+       status = omapi_connection_put_name (c, "client-hostname");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_string (c, lease -> client_hostname);
+       if (status != ISC_R_SUCCESS)
+               return status;
+
+       status = omapi_connection_put_name (c, "ddns-fwd-name");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_string (c, lease -> ddns_fwd_name);
+       if (status != ISC_R_SUCCESS)
+               return status;
+
+       status = omapi_connection_put_name (c, "ddns-rev-name");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_string (c, lease -> ddns_rev_name);
+       if (status != ISC_R_SUCCESS)
+               return status;
+
+       status = omapi_connection_put_name (c, "host");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_handle (c,
+                                             (omapi_object_t *)lease -> host);
+       if (status != ISC_R_SUCCESS)
+               return status;
+
+       status = omapi_connection_put_name (c, "subnet");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_handle
+               (c, (omapi_object_t *)lease -> subnet);
+       if (status != ISC_R_SUCCESS)
+               return status;
+
+       status = omapi_connection_put_name (c, "pool");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_handle (c,
+                                             (omapi_object_t *)lease -> pool);
+       if (status != ISC_R_SUCCESS)
+               return status;
+
+       status = omapi_connection_put_name (c, "billing-class");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_handle
+               (c, (omapi_object_t *)lease -> billing_class);
+       if (status != ISC_R_SUCCESS)
+               return status;
+
+       status = omapi_connection_put_name (c, "hardware-address");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_uint32 (c, lease -> hardware_addr.hlen);
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_copyin (c, lease -> hardware_addr.haddr,
+                                         lease -> hardware_addr.hlen);
+       if (status != ISC_R_SUCCESS)
+               return status;
+
+       status = omapi_connection_put_name (c, "hardware-type");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_uint32 (c, sizeof (int));
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_uint32 (c, lease -> hardware_addr.htype);
+       if (status != ISC_R_SUCCESS)
+               return status;
+
+       /* Write out the inner object, if any. */
+       if (h -> inner && h -> inner -> type -> stuff_values) {
+               status = ((*(h -> inner -> type -> stuff_values))
+                         (c, id, h -> inner));
+               if (status == ISC_R_SUCCESS)
+                       return status;
+       }
+
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_lease_lookup (omapi_object_t **lp,
+                               omapi_object_t *id, omapi_object_t *ref)
+{
+       omapi_value_t *tv = (omapi_value_t *)0;
+       isc_result_t status;
+       struct lease *lease;
+
+       /* First see if we were sent a handle. */
+       status = omapi_get_value_str (ref, id, "handle", &tv);
+       if (status == ISC_R_SUCCESS) {
+               status = omapi_handle_td_lookup (lp, tv -> value);
+
+               omapi_value_dereference (&tv, "dhcp_lease_lookup");
+               if (status != ISC_R_SUCCESS)
+                       return status;
+
+               /* Don't return the object if the type is wrong. */
+               if ((*lp) -> type != dhcp_type_lease) {
+                       omapi_object_dereference (lp, "dhcp_lease_lookup");
+                       return ISC_R_INVALIDARG;
+               }
+       }
+
+       /* Now look for an IP address. */
+       status = omapi_get_value_str (ref, id, "handle", &tv);
+       if (status == ISC_R_SUCCESS) {
+               /* If we already have a value, flag an error - only one
+                  key can be used for lookups at a time. */
+               if (*lp) {
+                       omapi_object_dereference (lp, "dhcp_lease_lookup");
+                       omapi_value_dereference (&tv, "dhcp_lease_lookup");
+                       return ISC_R_INVALIDARG;
+               }
+
+               lease = ((struct lease *)
+                        hash_lookup (lease_ip_addr_hash,
+                                     tv -> value -> u.buffer.value,
+                                     tv -> value -> u.buffer.len));
+
+               omapi_value_dereference (&tv, "dhcp_lease_lookup");
+
+               if (!lease)
+                       return ISC_R_NOTFOUND;
+
+               /* XXX fix so that hash lookup itself creates
+                  XXX the reference. */
+               omapi_object_reference (lp, (omapi_object_t *)lease,
+                                       "dhcp_lease_lookup");
+       }
+
+       /* Now look for a client identifier. */
+       status = omapi_get_value_str (ref, id, "dhcp-client-identifier", &tv);
+       if (status == ISC_R_SUCCESS) {
+               if (*lp) {
+                       omapi_object_dereference (lp, "dhcp_lease_lookup");
+                       omapi_value_dereference (&tv, "dhcp_lease_lookup");
+                       return ISC_R_INVALIDARG;
+               }
+
+               lease = ((struct lease *)
+                        hash_lookup (lease_uid_hash,
+                                     tv -> value -> u.buffer.value,
+                                     tv -> value -> u.buffer.len));
+               omapi_value_dereference (&tv, "dhcp_lease_lookup");
+                       
+               if (!lease)
+                       return ISC_R_NOTFOUND;
+               if (lease -> n_uid)
+                       return ISC_R_MULTIPLE;
+
+               /* XXX fix so that hash lookup itself creates
+                  XXX the reference. */
+               omapi_object_reference (lp, (omapi_object_t *)lease,
+                                       "dhcp_lease_lookup");
+       }
+
+       /* Now look for a hardware address. */
+       status = omapi_get_value_str (ref, id, "hardware-address", &tv);
+       if (status == ISC_R_SUCCESS) {
+               if (*lp) {
+                       omapi_object_dereference (lp, "dhcp_lease_lookup");
+                       omapi_value_dereference (&tv, "dhcp_lease_lookup");
+                       return ISC_R_INVALIDARG;
+               }
+
+               lease = ((struct lease *)
+                        hash_lookup (lease_uid_hash,
+                                     tv -> value -> u.buffer.value,
+                                     tv -> value -> u.buffer.len));
+               omapi_value_dereference (&tv, "dhcp_lease_lookup");
+                       
+               if (!lease)
+                       return ISC_R_NOTFOUND;
+               if (lease -> n_hw)
+                       return ISC_R_MULTIPLE;
+
+               /* XXX fix so that hash lookup itself creates
+                  XXX the reference. */
+               omapi_object_reference (lp, (omapi_object_t *)lease,
+                                       "dhcp_lease_lookup");
+       }
+
+       /* If we get to here without finding a lease, no valid key was
+          specified. */
+       if (!*lp)
+               return ISC_R_INVALIDARG;
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_lease_create (omapi_object_t **lp,
+                               omapi_object_t *id)
+{
+       return ISC_R_NOTIMPLEMENTED;
+}
+
+#if 0
+isc_result_t dhcp_group_set_value  (omapi_object_t *, omapi_object_t *,
+                                   omapi_data_string_t *,
+                                   omapi_typed_data_t *);
+isc_result_t dhcp_group_get_value (omapi_object_t *, omapi_object_t *,
+                                  omapi_data_string_t *,
+                                  omapi_value_t **); 
+isc_result_t dhcp_group_destroy (omapi_object_t *, char *);
+isc_result_t dhcp_group_signal_handler (omapi_object_t *, char *, va_list);
+isc_result_t dhcp_group_stuff_values (omapi_object_t *,
+                                     omapi_object_t *,
+                                     omapi_object_t *);
+isc_result_t dhcp_group_lookup (omapi_object_t **,
+                               omapi_object_t *, omapi_object_t *);
+#endif
+
+isc_result_t dhcp_host_set_value  (omapi_object_t *h,
+                                   omapi_object_t *id,
+                                   omapi_data_string_t *name,
+                                   omapi_typed_data_t *value)
+{
+       struct host_decl *host;
+       isc_result_t status;
+       int foo;
+
+       if (h -> type != omapi_type_message)
+               return ISC_R_INVALIDARG;
+       host = (struct host_decl *)h;
+
+       /* XXX For now, we can only set these values on new host objects. 
+          XXX Soon, we need to be able to update host objects. */
+       if (!omapi_ds_strcmp (name, "name")) {
+               if (host -> name)
+                       return ISC_R_EXISTS;
+               if (value -> type == omapi_datatype_data ||
+                   value -> type == omapi_datatype_string) {
+                       host -> name = malloc (value -> u.buffer.len + 1);
+                       if (!host -> name)
+                               return ISC_R_NOMEMORY;
+                       memcpy (host -> name,
+                               value -> u.buffer.value,
+                               value -> u.buffer.len);
+                       host -> name [value -> u.buffer.len] = 0;
+               } else
+                       return ISC_R_INVALIDARG;
+               return ISC_R_SUCCESS;
+       }
+
+       if (!omapi_ds_strcmp (name, "hardware-address")) {
+               if (host -> interface.hlen)
+                       return ISC_R_EXISTS;
+               if (value -> type == omapi_datatype_data ||
+                   value -> type == omapi_datatype_string) {
+                       if (value -> u.buffer.len >
+                           sizeof host -> interface.haddr)
+                               return ISC_R_INVALIDARG;
+                       memcpy (host -> interface.haddr,
+                               value -> u.buffer.value,
+                               value -> u.buffer.len);
+                       host -> interface.hlen = value -> u.buffer.len;
+               } else
+                       return ISC_R_INVALIDARG;
+               return ISC_R_SUCCESS;
+       }
+
+       if (!omapi_ds_strcmp (name, "hardware-type")) {
+               int type;
+               if (value -> type == omapi_datatype_data &&
+                   value -> u.buffer.len == sizeof type) {
+                       if (value -> u.buffer.len >
+                           sizeof host -> interface.haddr)
+                               return ISC_R_INVALIDARG;
+                       memcpy (&type,
+                               value -> u.buffer.value,
+                               value -> u.buffer.len);
+               } else if (value -> type == omapi_datatype_int)
+                       type = value -> u.integer;
+               else
+                       return ISC_R_INVALIDARG;
+               host -> interface.htype = type;
+               return ISC_R_SUCCESS;
+       }
+
+       if (!omapi_ds_strcmp (name, "dhcp-client-identifier")) {
+               if (host -> client_identifier.data)
+                       return ISC_R_EXISTS;
+               if (value -> type == omapi_datatype_data ||
+                   value -> type == omapi_datatype_string) {
+                       host -> client_identifier.len = value -> u.buffer.len;
+                       if (!buffer_allocate
+                           (&host -> client_identifier.buffer,
+                            host -> client_identifier.len,
+                            "dhcp_host_set_value"))
+                               return ISC_R_NOMEMORY;
+                       host -> client_identifier.data =
+                               &host -> client_identifier.buffer -> data [0];
+                       memcpy (host -> client_identifier.data,
+                               value -> u.buffer.value,
+                               host -> client_identifier.len);
+               } else
+                       return ISC_R_INVALIDARG;
+               return ISC_R_SUCCESS;
+       }
+
+       if (!omapi_ds_strcmp (name, "ip-address")) {
+               if (host -> fixed_addr)
+                       return ISC_R_EXISTS;
+               if (value -> type == omapi_datatype_data ||
+                   value -> type == omapi_datatype_string) {
+                       struct data_string ds;
+                       memset (&ds, 0, sizeof ds);
+                       ds.len = value -> u.buffer.len;
+                       if (!buffer_allocate (&ds.buffer, ds.len,
+                                             "dhcp_host_set_value"))
+                               return ISC_R_NOMEMORY;
+                       ds.data = (&host -> client_identifier.buffer ->
+                                  data [0]);
+                       memcpy (ds.data, value -> u.buffer.value, ds.len);
+                       if (!option_cache (&host -> fixed_addr,
+                                          &ds, (struct expression *)0,
+                                          (struct option *)0)) {
+                               data_string_forget (&ds,
+                                                   "dhcp_host_set_value");
+                               return ISC_R_NOMEMORY;
+                       }
+                       data_string_forget (&ds, "dhcp_host_set_value");
+               } else
+                       return ISC_R_INVALIDARG;
+               return ISC_R_SUCCESS;
+       }
+
+       /* Try to find some inner object that can take the value. */
+       if (h -> inner && h -> inner -> type -> set_value) {
+               status = ((*(h -> inner -> type -> set_value))
+                         (h -> inner, id, name, value));
+               if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED)
+                       return status;
+       }
+                         
+       return ISC_R_NOTFOUND;
+}
+
+
+isc_result_t dhcp_host_get_value (omapi_object_t *h, omapi_object_t *id,
+                                  omapi_data_string_t *name,
+                                  omapi_value_t **value)
+{
+       struct host_decl *host;
+       isc_result_t status;
+       struct data_string ip_addrs;
+
+       if (h -> type != dhcp_type_host)
+               return ISC_R_INVALIDARG;
+       host = (struct host_decl *)h;
+
+       if (!omapi_ds_strcmp (name, "ip-addresses")) {
+               memset (&ip_addrs, 0, sizeof ip_addrs);
+               if (host -> fixed_addr &&
+                   evaluate_option_cache (&ip_addrs, (struct packet *)0,
+                                          (struct lease *)0,
+                                          (struct option_state *)0,
+                                          (struct option_state *)0,
+                                          host -> fixed_addr)) {
+                       status = (omapi_make_const_value
+                                 (value, name, ip_addrs.data, ip_addrs.len,
+                                  "dhcp_host_get_value"));
+                       data_string_forget (&ip_addrs, "dhcp_host_get_value");
+                       return status;
+               }
+               return ISC_R_NOTFOUND;
+       }
+
+       if (!omapi_ds_strcmp (name, "dhcp-client-identifier")) {
+               if (!host -> client_identifier.len)
+                       return ISC_R_NOTFOUND;
+               return omapi_make_const_value (value, name,
+                                              host -> client_identifier.data,
+                                              host -> client_identifier.len,
+                                              "dhcp_host_get_value");
+       }
+
+       if (!omapi_ds_strcmp (name, "name"))
+               return omapi_make_string_value (value, name, host -> name,
+                                               "dhcp_host_get_value");
+
+       if (!omapi_ds_strcmp (name, "hardware-address")) {
+               if (!host -> interface.hlen)
+                       return ISC_R_NOTFOUND;
+               return omapi_make_const_value (value, name,
+                                              host -> interface.haddr,
+                                              host -> interface.hlen,
+                                              "dhcp_host_get_value");
+       }
+
+       if (!omapi_ds_strcmp (name, "hardware-type")) {
+               if (!host -> interface.hlen)
+                       return ISC_R_NOTFOUND;
+               return omapi_make_int_value (value, name,
+                                            host -> interface.htype,
+                                            "dhcp_host_get_value");
+       }
+
+       /* Try to find some inner object that can take the value. */
+       if (h -> inner && h -> inner -> type -> get_value) {
+               status = ((*(h -> inner -> type -> get_value))
+                         (h -> inner, id, name, value));
+               if (status == ISC_R_SUCCESS)
+                       return status;
+       }
+       return ISC_R_NOTFOUND;
+}
+
+isc_result_t dhcp_host_destroy (omapi_object_t *h, char *name)
+{
+       struct host_decl *host;
+       isc_result_t status;
+
+       if (h -> type != dhcp_type_host)
+               return ISC_R_INVALIDARG;
+       host = (struct host_decl *)h;
+
+       /* Currently, this is completely hopeless - have to complete
+           reference counting support for server OMAPI objects. */
+
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_host_signal_handler (omapi_object_t *h,
+                                       char *name, va_list ap)
+{
+       struct host_decl *host;
+       isc_result_t status;
+
+       if (h -> type != dhcp_type_host)
+               return ISC_R_INVALIDARG;
+       host = (struct host_decl *)h;
+
+       if (!strcmp (name, "updated")) {
+               if (!host -> name) {
+                       char hnbuf [64];
+                       sprintf (hnbuf, "nh%08lx%08x",
+                                cur_time, (u_int32_t)host);
+                       host -> name = malloc (strlen (hnbuf) + 1);
+                       if (!host -> name)
+                               return ISC_R_NOMEMORY;
+                       strcpy (host -> name, hnbuf);
+               }
+               enter_host (host, 1);
+               if (!write_host (host))
+                       return ISC_R_IOERROR;
+       }
+
+       /* Try to find some inner object that can take the value. */
+       if (h -> inner && h -> inner -> type -> get_value) {
+               status = ((*(h -> inner -> type -> signal_handler))
+                         (h -> inner, name, ap));
+               if (status == ISC_R_SUCCESS)
+                       return status;
+       }
+       return ISC_R_NOTFOUND;
+}
+
+isc_result_t dhcp_host_stuff_values (omapi_object_t *c,
+                                     omapi_object_t *id,
+                                     omapi_object_t *h)
+{
+       struct host_decl *host;
+       isc_result_t status;
+       struct data_string ip_addrs;
+
+       if (h -> type != dhcp_type_host)
+               return ISC_R_INVALIDARG;
+       host = (struct host_decl *)h;
+
+       /* Write out all the values. */
+
+       memset (&ip_addrs, 0, sizeof ip_addrs);
+       if (host -> fixed_addr &&
+           evaluate_option_cache (&ip_addrs, (struct packet *)0,
+                                  (struct lease *)0,
+                                  (struct option_state *)0,
+                                  (struct option_state *)0,
+                                  host -> fixed_addr)) {
+               status = omapi_connection_put_name (c, "ip-address");
+               if (status != ISC_R_SUCCESS)
+                       return status;
+               status = omapi_connection_put_uint32 (c, ip_addrs.len);
+               if (status != ISC_R_SUCCESS)
+                       return status;
+               status = omapi_connection_copyin (c,
+                                                 ip_addrs.data, ip_addrs.len);
+               if (status != ISC_R_SUCCESS)
+                       return status;
+       }
+
+       if (host -> client_identifier.len) {
+               status = omapi_connection_put_name (c,
+                                                   "dhcp-client-identifier");
+               if (status != ISC_R_SUCCESS)
+                       return status;
+               status = (omapi_connection_put_uint32
+                         (c, host -> client_identifier.len));
+               if (status != ISC_R_SUCCESS)
+                       return status;
+       }
+
+       status = omapi_connection_put_name (c, "name");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_string (c, host -> name);
+       if (status != ISC_R_SUCCESS)
+               return status;
+
+       status = omapi_connection_put_name (c, "hardware-address");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_uint32 (c, host -> interface.hlen);
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_copyin (c, host -> interface.haddr,
+                                         host -> interface.hlen);
+       if (status != ISC_R_SUCCESS)
+               return status;
+
+       status = omapi_connection_put_name (c, "hardware-type");
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_uint32 (c, sizeof (int));
+       if (status != ISC_R_SUCCESS)
+               return status;
+       status = omapi_connection_put_uint32 (c, host -> interface.htype);
+       if (status != ISC_R_SUCCESS)
+               return status;
+
+       /* Write out the inner object, if any. */
+       if (h -> inner && h -> inner -> type -> stuff_values) {
+               status = ((*(h -> inner -> type -> stuff_values))
+                         (c, id, h -> inner));
+               if (status == ISC_R_SUCCESS)
+                       return status;
+       }
+
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_host_lookup (omapi_object_t **lp,
+                               omapi_object_t *id, omapi_object_t *ref)
+{
+       omapi_value_t *tv = (omapi_value_t *)0;
+       isc_result_t status;
+       struct host_decl *host;
+
+       /* First see if we were sent a handle. */
+       status = omapi_get_value_str (ref, id, "handle", &tv);
+       if (status == ISC_R_SUCCESS) {
+               status = omapi_handle_td_lookup (lp, tv -> value);
+
+               omapi_value_dereference (&tv, "dhcp_host_lookup");
+               if (status != ISC_R_SUCCESS)
+                       return status;
+
+               /* Don't return the object if the type is wrong. */
+               if ((*lp) -> type != dhcp_type_host) {
+                       omapi_object_dereference (lp, "dhcp_host_lookup");
+                       return ISC_R_INVALIDARG;
+               }
+       }
+
+       /* Now look for a client identifier. */
+       status = omapi_get_value_str (ref, id, "dhcp-client-identifier", &tv);
+       if (status == ISC_R_SUCCESS) {
+               if (*lp) {
+                       omapi_object_dereference (lp, "dhcp_host_lookup");
+                       omapi_value_dereference (&tv, "dhcp_host_lookup");
+                       return ISC_R_INVALIDARG;
+               }
+
+               host = ((struct host_decl *)
+                        hash_lookup (host_uid_hash,
+                                     tv -> value -> u.buffer.value,
+                                     tv -> value -> u.buffer.len));
+               omapi_value_dereference (&tv, "dhcp_host_lookup");
+                       
+               if (!host)
+                       return ISC_R_NOTFOUND;
+
+               /* XXX fix so that hash lookup itself creates
+                  XXX the reference. */
+               omapi_object_reference (lp, (omapi_object_t *)host,
+                                       "dhcp_host_lookup");
+       }
+
+       /* Now look for a hardware address. */
+       status = omapi_get_value_str (ref, id, "hardware-address", &tv);
+       if (status == ISC_R_SUCCESS) {
+               if (*lp) {
+                       omapi_object_dereference (lp, "dhcp_host_lookup");
+                       omapi_value_dereference (&tv, "dhcp_host_lookup");
+                       return ISC_R_INVALIDARG;
+               }
+
+               host = ((struct host_decl *)
+                        hash_lookup (host_hw_addr_hash,
+                                     tv -> value -> u.buffer.value,
+                                     tv -> value -> u.buffer.len));
+               omapi_value_dereference (&tv, "dhcp_host_lookup");
+                       
+               if (!host)
+                       return ISC_R_NOTFOUND;
+
+               /* XXX fix so that hash lookup itself creates
+                  XXX the reference. */
+               omapi_object_reference (lp, (omapi_object_t *)host,
+                                       "dhcp_host_lookup");
+       }
+
+       /* If we get to here without finding a host, no valid key was
+          specified. */
+       if (!*lp)
+               return ISC_R_INVALIDARG;
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_host_create (omapi_object_t **lp,
+                              omapi_object_t *id)
+{
+       struct host_decl *hp;
+       hp = (struct host_decl *)dmalloc (sizeof (struct host_decl),
+                                         "dhcp_host_create");
+       if (!hp)
+               return ISC_R_NOMEMORY;
+       memset (hp, 0, sizeof *hp);
+       hp -> refcnt = 0;
+       return omapi_object_reference (lp, (omapi_object_t *)hp,
+                                      "dhcp_host_create");
+}
+
+isc_result_t dhcp_pool_set_value  (omapi_object_t *h,
+                                   omapi_object_t *id,
+                                   omapi_data_string_t *name,
+                                   omapi_typed_data_t *value)
+{
+       struct pool *pool;
+       isc_result_t status;
+       int foo;
+
+       if (h -> type != omapi_type_message)
+               return ISC_R_INVALIDARG;
+       pool = (struct pool *)h;
+
+       /* No values to set yet. */
+
+       /* Try to find some inner object that can take the value. */
+       if (h -> inner && h -> inner -> type -> set_value) {
+               status = ((*(h -> inner -> type -> set_value))
+                         (h -> inner, id, name, value));
+               if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED)
+                       return status;
+       }
+                         
+       return ISC_R_NOTFOUND;
+}
+
+
+isc_result_t dhcp_pool_get_value (omapi_object_t *h, omapi_object_t *id,
+                                  omapi_data_string_t *name,
+                                  omapi_value_t **value)
+{
+       struct pool *pool;
+       isc_result_t status;
+
+       if (h -> type != dhcp_type_pool)
+               return ISC_R_INVALIDARG;
+       pool = (struct pool *)h;
+
+       /* No values to get yet. */
+
+       /* Try to find some inner object that can provide the value. */
+       if (h -> inner && h -> inner -> type -> get_value) {
+               status = ((*(h -> inner -> type -> get_value))
+                         (h -> inner, id, name, value));
+               if (status == ISC_R_SUCCESS)
+                       return status;
+       }
+       return ISC_R_NOTFOUND;
+}
+
+isc_result_t dhcp_pool_destroy (omapi_object_t *h, char *name)
+{
+       struct pool *pool;
+       isc_result_t status;
+
+       if (h -> type != dhcp_type_pool)
+               return ISC_R_INVALIDARG;
+       pool = (struct pool *)h;
+
+       /* Can't destroy pools yet. */
+
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_pool_signal_handler (omapi_object_t *h,
+                                       char *name, va_list ap)
+{
+       struct pool *pool;
+       isc_result_t status;
+
+       if (h -> type != dhcp_type_pool)
+               return ISC_R_INVALIDARG;
+       pool = (struct pool *)h;
+
+       /* Can't write pools yet. */
+
+       /* Try to find some inner object that can take the value. */
+       if (h -> inner && h -> inner -> type -> get_value) {
+               status = ((*(h -> inner -> type -> signal_handler))
+                         (h -> inner, name, ap));
+               if (status == ISC_R_SUCCESS)
+                       return status;
+       }
+       return ISC_R_NOTFOUND;
+}
+
+isc_result_t dhcp_pool_stuff_values (omapi_object_t *c,
+                                     omapi_object_t *id,
+                                     omapi_object_t *h)
+{
+       struct pool *pool;
+       isc_result_t status;
+
+       if (h -> type != dhcp_type_pool)
+               return ISC_R_INVALIDARG;
+       pool = (struct pool *)h;
+
+       /* Can't stuff pool values yet. */
+
+       /* Write out the inner object, if any. */
+       if (h -> inner && h -> inner -> type -> stuff_values) {
+               status = ((*(h -> inner -> type -> stuff_values))
+                         (c, id, h -> inner));
+               if (status == ISC_R_SUCCESS)
+                       return status;
+       }
+
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_pool_lookup (omapi_object_t **lp,
+                               omapi_object_t *id, omapi_object_t *ref)
+{
+       omapi_value_t *tv = (omapi_value_t *)0;
+       isc_result_t status;
+       struct pool *pool;
+
+       /* Can't look up pools yet. */
+
+       /* If we get to here without finding a pool, no valid key was
+          specified. */
+       if (!*lp)
+               return ISC_R_INVALIDARG;
+       return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_pool_create (omapi_object_t **lp,
+                               omapi_object_t *id)
+{
+       return ISC_R_NOTIMPLEMENTED;
+}
+