aboutsummaryrefslogtreecommitdiff
path: root/server/omapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/omapi.c')
-rw-r--r--server/omapi.c2584
1 files changed, 2584 insertions, 0 deletions
diff --git a/server/omapi.c b/server/omapi.c
new file mode 100644
index 0000000..bbddaf9
--- /dev/null
+++ b/server/omapi.c
@@ -0,0 +1,2584 @@
+/* omapi.c
+
+ OMAPI object interfaces for the DHCP server. */
+
+/*
+ * Copyright (c) 2004-2010 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1999-2003 by Internet Software Consortium
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Internet Systems Consortium, Inc.
+ * 950 Charter Street
+ * Redwood City, CA 94063
+ * <info@isc.org>
+ * https://www.isc.org/
+ *
+ * This software has been written for Internet Systems Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about Internet Systems Consortium, see
+ * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+/* 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 */
+
+#include "dhcpd.h"
+#include <omapip/omapip_p.h>
+
+static isc_result_t class_lookup (omapi_object_t **,
+ omapi_object_t *, omapi_object_t *,
+ omapi_object_type_t *);
+
+omapi_object_type_t *dhcp_type_lease;
+omapi_object_type_t *dhcp_type_pool;
+omapi_object_type_t *dhcp_type_class;
+omapi_object_type_t *dhcp_type_subclass;
+omapi_object_type_t *dhcp_type_host;
+#if defined (FAILOVER_PROTOCOL)
+omapi_object_type_t *dhcp_type_failover_state;
+omapi_object_type_t *dhcp_type_failover_link;
+omapi_object_type_t *dhcp_type_failover_listener;
+#endif
+
+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,
+ dhcp_lease_remove,
+#if defined (COMPACT_LEASES)
+ dhcp_lease_free,
+ dhcp_lease_get,
+#else
+ 0, 0,
+#endif
+ 0,
+ sizeof (struct lease),
+ 0, RC_LEASE);
+ 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_class,
+ "class",
+ dhcp_class_set_value,
+ dhcp_class_get_value,
+ dhcp_class_destroy,
+ dhcp_class_signal_handler,
+ dhcp_class_stuff_values,
+ dhcp_class_lookup,
+ dhcp_class_create,
+ dhcp_class_remove, 0, 0, 0,
+ sizeof (struct class), 0,
+ RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ log_fatal ("Can't register class object type: %s",
+ isc_result_totext (status));
+
+ status = omapi_object_type_register (&dhcp_type_subclass,
+ "subclass",
+ dhcp_subclass_set_value,
+ dhcp_subclass_get_value,
+ dhcp_class_destroy,
+ dhcp_subclass_signal_handler,
+ dhcp_subclass_stuff_values,
+ dhcp_subclass_lookup,
+ dhcp_subclass_create,
+ dhcp_subclass_remove, 0, 0, 0,
+ sizeof (struct class), 0, RC_MISC);
+ if (status != ISC_R_SUCCESS)
+ log_fatal ("Can't register subclass 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,
+ dhcp_pool_remove, 0, 0, 0,
+ sizeof (struct pool), 0, RC_MISC);
+
+ if (status != ISC_R_SUCCESS)
+ log_fatal ("Can't register pool 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,
+ dhcp_host_remove, 0, 0, 0,
+ sizeof (struct host_decl),
+ 0, RC_MISC);
+
+ if (status != ISC_R_SUCCESS)
+ log_fatal ("Can't register host object type: %s",
+ isc_result_totext (status));
+
+#if defined (FAILOVER_PROTOCOL)
+ status = omapi_object_type_register (&dhcp_type_failover_state,
+ "failover-state",
+ dhcp_failover_state_set_value,
+ dhcp_failover_state_get_value,
+ dhcp_failover_state_destroy,
+ dhcp_failover_state_signal,
+ dhcp_failover_state_stuff,
+ dhcp_failover_state_lookup,
+ dhcp_failover_state_create,
+ dhcp_failover_state_remove,
+ 0, 0, 0,
+ sizeof (dhcp_failover_state_t),
+ 0, RC_MISC);
+
+ if (status != ISC_R_SUCCESS)
+ log_fatal ("Can't register failover state object type: %s",
+ isc_result_totext (status));
+
+ status = omapi_object_type_register (&dhcp_type_failover_link,
+ "failover-link",
+ dhcp_failover_link_set_value,
+ dhcp_failover_link_get_value,
+ dhcp_failover_link_destroy,
+ dhcp_failover_link_signal,
+ dhcp_failover_link_stuff_values,
+ 0, 0, 0, 0, 0, 0,
+ sizeof (dhcp_failover_link_t), 0,
+ RC_MISC);
+
+ if (status != ISC_R_SUCCESS)
+ log_fatal ("Can't register failover link object type: %s",
+ isc_result_totext (status));
+
+ status = omapi_object_type_register (&dhcp_type_failover_listener,
+ "failover-listener",
+ dhcp_failover_listener_set_value,
+ dhcp_failover_listener_get_value,
+ dhcp_failover_listener_destroy,
+ dhcp_failover_listener_signal,
+ dhcp_failover_listener_stuff,
+ 0, 0, 0, 0, 0, 0,
+ sizeof
+ (dhcp_failover_listener_t), 0,
+ RC_MISC);
+
+ if (status != ISC_R_SUCCESS)
+ log_fatal ("Can't register failover listener object type: %s",
+ isc_result_totext (status));
+#endif /* FAILOVER_PROTOCOL */
+}
+
+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;
+
+ if (h -> type != dhcp_type_lease)
+ return DHCP_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 state. */
+ if (!omapi_ds_strcmp (name, "state")) {
+ unsigned long bar;
+ const char *ols, *nls;
+ status = omapi_get_int_value (&bar, value);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ if (bar < 1 || bar > FTS_LAST)
+ return DHCP_R_INVALIDARG;
+ nls = binding_state_names [bar - 1];
+ if (lease -> binding_state >= 1 &&
+ lease -> binding_state <= FTS_LAST)
+ ols = binding_state_names [lease -> binding_state - 1];
+ else
+ ols = "unknown state";
+
+ if (lease -> binding_state != bar) {
+ lease -> next_binding_state = bar;
+ if (supersede_lease (lease, 0, 1, 1, 1)) {
+ log_info ("lease %s state changed from %s to %s",
+ piaddr(lease->ip_addr), ols, nls);
+ return ISC_R_SUCCESS;
+ }
+ log_info ("lease %s state change from %s to %s failed.",
+ piaddr (lease -> ip_addr), ols, nls);
+ return ISC_R_IOERROR;
+ }
+ return DHCP_R_UNCHANGED;
+ } else if (!omapi_ds_strcmp (name, "ip-address")) {
+ return ISC_R_NOPERM;
+ } else if (!omapi_ds_strcmp (name, "dhcp-client-identifier")) {
+ return DHCP_R_UNCHANGED; /* XXX take change. */
+ } else if (!omapi_ds_strcmp (name, "hostname")) {
+ return DHCP_R_UNCHANGED; /* XXX take change. */
+ } else if (!omapi_ds_strcmp (name, "client-hostname")) {
+ return DHCP_R_UNCHANGED; /* XXX take change. */
+ } else if (!omapi_ds_strcmp (name, "host")) {
+ return DHCP_R_UNCHANGED; /* XXX take change. */
+ } else if (!omapi_ds_strcmp (name, "subnet")) {
+ return DHCP_R_INVALIDARG;
+ } else if (!omapi_ds_strcmp (name, "pool")) {
+ return ISC_R_NOPERM;
+ } else if (!omapi_ds_strcmp (name, "starts")) {
+ return ISC_R_NOPERM;
+ } else if (!omapi_ds_strcmp (name, "ends")) {
+ unsigned long lease_end, old_lease_end;
+ status = omapi_get_int_value (&lease_end, value);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ old_lease_end = lease->ends;
+ lease->ends = lease_end;
+ if (supersede_lease (lease, 0, 1, 1, 1)) {
+ log_info ("lease %s end changed from %lu to %lu",
+ piaddr(lease->ip_addr), old_lease_end, lease_end);
+ return ISC_R_SUCCESS;
+ }
+ log_info ("lease %s end change from %lu to %lu failed",
+ piaddr(lease->ip_addr), old_lease_end, lease_end);
+ return ISC_R_IOERROR;
+ } else if (!omapi_ds_strcmp(name, "flags")) {
+ u_int8_t oldflags;
+
+ if (value->type != omapi_datatype_data)
+ return DHCP_R_INVALIDARG;
+
+ oldflags = lease->flags;
+ lease->flags = (value->u.buffer.value[0] & EPHEMERAL_FLAGS) |
+ (lease->flags & ~EPHEMERAL_FLAGS);
+ if(oldflags == lease->flags)
+ return ISC_R_SUCCESS;
+ if (!supersede_lease(lease, NULL, 1, 1, 1)) {
+ log_error("Failed to update flags for lease %s.",
+ piaddr(lease->ip_addr));
+ return ISC_R_IOERROR;
+ }
+ return ISC_R_SUCCESS;
+ } else if (!omapi_ds_strcmp (name, "billing-class")) {
+ return DHCP_R_UNCHANGED; /* XXX carefully allow change. */
+ } else if (!omapi_ds_strcmp (name, "hardware-address")) {
+ return DHCP_R_UNCHANGED; /* XXX take change. */
+ } else if (!omapi_ds_strcmp (name, "hardware-type")) {
+ return DHCP_R_UNCHANGED; /* XXX take change. */
+ } else if (lease -> scope) {
+ status = binding_scope_set_value (lease -> scope, 0, name, value);
+ if (status == ISC_R_SUCCESS) {
+ if (write_lease (lease) && commit_leases ())
+ return ISC_R_SUCCESS;
+ return ISC_R_IOERROR;
+ }
+ }
+
+ /* 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 == DHCP_R_UNCHANGED)
+ return status;
+ }
+
+ if (!lease -> scope) {
+ if (!binding_scope_allocate (&lease -> scope, MDL))
+ return ISC_R_NOMEMORY;
+ }
+ status = binding_scope_set_value (lease -> scope, 1, name, value);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ if (write_lease (lease) && commit_leases ())
+ return ISC_R_SUCCESS;
+ return ISC_R_IOERROR;
+}
+
+
+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 DHCP_R_INVALIDARG;
+ lease = (struct lease *)h;
+
+ if (!omapi_ds_strcmp (name, "state"))
+ return omapi_make_int_value (value, name,
+ (int)lease -> binding_state, MDL);
+ else if (!omapi_ds_strcmp (name, "ip-address"))
+ return omapi_make_const_value (value, name,
+ lease -> ip_addr.iabuf,
+ lease -> ip_addr.len, MDL);
+ else if (!omapi_ds_strcmp (name, "dhcp-client-identifier")) {
+ return omapi_make_const_value (value, name,
+ lease -> uid,
+ lease -> uid_len, MDL);
+ } else if (!omapi_ds_strcmp (name, "client-hostname")) {
+ if (lease -> client_hostname)
+ return omapi_make_string_value
+ (value, name, lease -> client_hostname, MDL);
+ return ISC_R_NOTFOUND;
+ } else if (!omapi_ds_strcmp (name, "host")) {
+ if (lease -> host)
+ return omapi_make_handle_value
+ (value, name,
+ ((omapi_object_t *)lease -> host), MDL);
+ } else if (!omapi_ds_strcmp (name, "subnet"))
+ return omapi_make_handle_value (value, name,
+ ((omapi_object_t *)
+ lease -> subnet), MDL);
+ else if (!omapi_ds_strcmp (name, "pool"))
+ return omapi_make_handle_value (value, name,
+ ((omapi_object_t *)
+ lease -> pool), MDL);
+ else if (!omapi_ds_strcmp (name, "billing-class")) {
+ if (lease -> billing_class)
+ return omapi_make_handle_value
+ (value, name,
+ ((omapi_object_t *)lease -> billing_class),
+ MDL);
+ return ISC_R_NOTFOUND;
+ } else if (!omapi_ds_strcmp (name, "hardware-address")) {
+ if (lease -> hardware_addr.hlen)
+ return omapi_make_const_value
+ (value, name, &lease -> hardware_addr.hbuf [1],
+ (unsigned)(lease -> hardware_addr.hlen - 1),
+ MDL);
+ return ISC_R_NOTFOUND;
+ } else if (!omapi_ds_strcmp (name, "hardware-type")) {
+ if (lease -> hardware_addr.hlen)
+ return omapi_make_int_value
+ (value, name, lease -> hardware_addr.hbuf [0],
+ MDL);
+ return ISC_R_NOTFOUND;
+ } else if (lease -> scope) {
+ status = binding_scope_get_value (value, lease -> scope, name);
+ if (status != ISC_R_NOTFOUND)
+ return status;
+ }
+
+ /* 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 DHCP_R_UNKNOWNATTRIBUTE;
+}
+
+isc_result_t dhcp_lease_destroy (omapi_object_t *h, const char *file, int line)
+{
+ struct lease *lease;
+
+ if (h -> type != dhcp_type_lease)
+ return DHCP_R_INVALIDARG;
+ lease = (struct lease *)h;
+
+ if (lease -> uid)
+ uid_hash_delete (lease);
+ hw_hash_delete (lease);
+
+ if (lease -> on_release)
+ executable_statement_dereference (&lease -> on_release,
+ file, line);
+ if (lease -> on_expiry)
+ executable_statement_dereference (&lease -> on_expiry,
+ file, line);
+ if (lease -> on_commit)
+ executable_statement_dereference (&lease -> on_commit,
+ file, line);
+ if (lease -> scope)
+ binding_scope_dereference (&lease -> scope, file, line);
+
+ if (lease -> agent_options)
+ option_chain_head_dereference (&lease -> agent_options,
+ file, line);
+ if (lease -> uid && lease -> uid != lease -> uid_buf) {
+ dfree (lease -> uid, MDL);
+ lease -> uid = &lease -> uid_buf [0];
+ lease -> uid_len = 0;
+ }
+
+ if (lease -> client_hostname) {
+ dfree (lease -> client_hostname, MDL);
+ lease -> client_hostname = (char *)0;
+ }
+
+ if (lease -> host)
+ host_dereference (&lease -> host, file, line);
+ if (lease -> subnet)
+ subnet_dereference (&lease -> subnet, file, line);
+ if (lease -> pool)
+ pool_dereference (&lease -> pool, file, line);
+
+ if (lease -> state) {
+ free_lease_state (lease -> state, file, line);
+ lease -> state = (struct lease_state *)0;
+
+ cancel_timeout (lease_ping_timeout, lease);
+ --outstanding_pings; /* XXX */
+ }
+
+ if (lease -> billing_class)
+ class_dereference
+ (&lease -> billing_class, file, line);
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ /* XXX we should never be destroying a lease with a next
+ XXX pointer except on exit... */
+ if (lease -> next)
+ lease_dereference (&lease -> next, file, line);
+ if (lease -> n_hw)
+ lease_dereference (&lease -> n_hw, file, line);
+ if (lease -> n_uid)
+ lease_dereference (&lease -> n_uid, file, line);
+ if (lease -> next_pending)
+ lease_dereference (&lease -> next_pending, file, line);
+#endif
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_lease_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ struct lease *lease;
+ isc_result_t status;
+
+ if (h -> type != dhcp_type_lease)
+ return DHCP_R_INVALIDARG;
+ lease = (struct lease *)h;
+
+ if (!strcmp (name, "updated"))
+ return ISC_R_SUCCESS;
+
+ /* Try to find some inner object that can take the value. */
+ if (h -> inner && h -> inner -> type -> signal_handler) {
+ 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)
+{
+ u_int32_t bouncer;
+ struct lease *lease;
+ isc_result_t status;
+ u_int8_t flagbuf;
+
+ if (h -> type != dhcp_type_lease)
+ return DHCP_R_INVALIDARG;
+ lease = (struct lease *)h;
+
+ /* Write out all the values. */
+
+ status = omapi_connection_put_name (c, "state");
+ 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 -> binding_state);
+ 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;
+
+ if (lease -> uid_len) {
+ 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;
+ }
+ }
+
+ if (lease -> client_hostname) {
+ 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;
+ }
+
+ if (lease -> host) {
+ 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;
+
+ if (lease -> billing_class) {
+ 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;
+ }
+
+ if (lease -> hardware_addr.hlen) {
+ status = omapi_connection_put_name (c, "hardware-address");
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = (omapi_connection_put_uint32
+ (c,
+ (unsigned long)(lease -> hardware_addr.hlen - 1)));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = (omapi_connection_copyin
+ (c, &lease -> hardware_addr.hbuf [1],
+ (unsigned long)(lease -> hardware_addr.hlen - 1)));
+
+ 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.hbuf [0]);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+
+ /* TIME values may be 64-bit, depending on system architecture.
+ * OMAPI must be system independent, both in terms of transmitting
+ * bytes on the wire in network byte order, and in terms of being
+ * readable and usable by both systems.
+ *
+ * XXX: In a future feature release, a put_int64() should be made
+ * to exist, and perhaps a put_time() wrapper that selects which
+ * to use based upon sizeof(TIME). In the meantime, use existing,
+ * 32-bit, code.
+ */
+ bouncer = (u_int32_t)lease->ends;
+ status = omapi_connection_put_name(c, "ends");
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_uint32(c, sizeof(bouncer));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_uint32(c, bouncer);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ bouncer = (u_int32_t)lease->starts;
+ status = omapi_connection_put_name(c, "starts");
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_uint32(c, sizeof(bouncer));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_uint32(c, bouncer);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ bouncer = (u_int32_t)lease->tstp;
+ status = omapi_connection_put_name(c, "tstp");
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_uint32(c, sizeof(bouncer));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_uint32(c, bouncer);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ bouncer = (u_int32_t)lease->tsfp;
+ status = omapi_connection_put_name(c, "tsfp");
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_uint32(c, sizeof(bouncer));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_uint32(c, bouncer);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ bouncer = (u_int32_t)lease->atsfp;
+ status = omapi_connection_put_name(c, "atsfp");
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_uint32(c, sizeof(bouncer));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_uint32(c, bouncer);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ bouncer = (u_int32_t)lease->cltt;
+ status = omapi_connection_put_name(c, "cltt");
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_uint32(c, sizeof(bouncer));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_uint32(c, bouncer);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ status = omapi_connection_put_name (c, "flags");
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_put_uint32(c, sizeof(flagbuf));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ flagbuf = lease->flags & EPHEMERAL_FLAGS;
+ status = omapi_connection_copyin(c, &flagbuf, sizeof(flagbuf));
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ if (lease -> scope) {
+ status = binding_scope_stuff_values (c, lease -> scope);
+ 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;
+
+ if (!ref)
+ return DHCP_R_NOKEYS;
+
+ /* 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, MDL);
+ 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, MDL);
+ return DHCP_R_INVALIDARG;
+ }
+ }
+
+ /* Now look for an IP address. */
+ status = omapi_get_value_str (ref, id, "ip-address", &tv);
+ if (status == ISC_R_SUCCESS) {
+ lease = (struct lease *)0;
+ lease_ip_hash_lookup(&lease, lease_ip_addr_hash,
+ tv->value->u.buffer.value,
+ tv->value->u.buffer.len, MDL);
+
+ omapi_value_dereference (&tv, MDL);
+
+ /* If we already have a lease, and it's not the same one,
+ then the query was invalid. */
+ if (*lp && *lp != (omapi_object_t *)lease) {
+ omapi_object_dereference (lp, MDL);
+ lease_dereference (&lease, MDL);
+ return DHCP_R_KEYCONFLICT;
+ } else if (!lease) {
+ if (*lp)
+ omapi_object_dereference (lp, MDL);
+ return ISC_R_NOTFOUND;
+ } else if (!*lp) {
+ /* XXX fix so that hash lookup itself creates
+ XXX the reference. */
+ omapi_object_reference (lp,
+ (omapi_object_t *)lease, MDL);
+ lease_dereference (&lease, MDL);
+ }
+ }
+
+ /* Now look for a client identifier. */
+ status = omapi_get_value_str (ref, id, "dhcp-client-identifier", &tv);
+ if (status == ISC_R_SUCCESS) {
+ lease = (struct lease *)0;
+ lease_id_hash_lookup(&lease, lease_uid_hash,
+ tv->value->u.buffer.value,
+ tv->value->u.buffer.len, MDL);
+ omapi_value_dereference (&tv, MDL);
+
+ if (*lp && *lp != (omapi_object_t *)lease) {
+ omapi_object_dereference (lp, MDL);
+ lease_dereference (&lease, MDL);
+ return DHCP_R_KEYCONFLICT;
+ } else if (!lease) {
+ if (*lp)
+ omapi_object_dereference (lp, MDL);
+ return ISC_R_NOTFOUND;
+ } else if (lease -> n_uid) {
+ if (*lp)
+ omapi_object_dereference (lp, MDL);
+ return DHCP_R_MULTIPLE;
+ } else if (!*lp) {
+ /* XXX fix so that hash lookup itself creates
+ XXX the reference. */
+ omapi_object_reference (lp,
+ (omapi_object_t *)lease, MDL);
+ lease_dereference (&lease, MDL);
+ }
+ }
+
+ /* Now look for a hardware address. */
+ status = omapi_get_value_str (ref, id, "hardware-address", &tv);
+ if (status == ISC_R_SUCCESS) {
+ unsigned char *haddr;
+ unsigned int len;
+
+ len = tv -> value -> u.buffer.len + 1;
+ haddr = dmalloc (len, MDL);
+ if (!haddr) {
+ omapi_value_dereference (&tv, MDL);
+ return ISC_R_NOMEMORY;
+ }
+
+ memcpy (haddr + 1, tv -> value -> u.buffer.value, len - 1);
+ omapi_value_dereference (&tv, MDL);
+
+ status = omapi_get_value_str (ref, id, "hardware-type", &tv);
+ if (status == ISC_R_SUCCESS) {
+ if (tv -> value -> type == omapi_datatype_data) {
+ if ((tv -> value -> u.buffer.len != 4) ||
+ (tv -> value -> u.buffer.value[0] != 0) ||
+ (tv -> value -> u.buffer.value[1] != 0) ||
+ (tv -> value -> u.buffer.value[2] != 0)) {
+ omapi_value_dereference (&tv, MDL);
+ dfree (haddr, MDL);
+ return DHCP_R_INVALIDARG;
+ }
+
+ haddr[0] = tv -> value -> u.buffer.value[3];
+ } else if (tv -> value -> type == omapi_datatype_int) {
+ haddr[0] = (unsigned char)
+ tv -> value -> u.integer;
+ } else {
+ omapi_value_dereference (&tv, MDL);
+ dfree (haddr, MDL);
+ return DHCP_R_INVALIDARG;
+ }
+
+ omapi_value_dereference (&tv, MDL);
+ } else {
+ /* If no hardware-type is specified, default to
+ ethernet. This may or may not be a good idea,
+ but Telus is currently relying on this behavior.
+ - DPN */
+ haddr[0] = HTYPE_ETHER;
+ }
+
+ lease = (struct lease *)0;
+ lease_id_hash_lookup(&lease, lease_hw_addr_hash, haddr, len,
+ MDL);
+ dfree (haddr, MDL);
+
+ if (*lp && *lp != (omapi_object_t *)lease) {
+ omapi_object_dereference (lp, MDL);
+ lease_dereference (&lease, MDL);
+ return DHCP_R_KEYCONFLICT;
+ } else if (!lease) {
+ if (*lp)
+ omapi_object_dereference (lp, MDL);
+ return ISC_R_NOTFOUND;
+ } else if (lease -> n_hw) {
+ if (*lp)
+ omapi_object_dereference (lp, MDL);
+ lease_dereference (&lease, MDL);
+ return DHCP_R_MULTIPLE;
+ } else if (!*lp) {
+ /* XXX fix so that hash lookup itself creates
+ XXX the reference. */
+ omapi_object_reference (lp,
+ (omapi_object_t *)lease, MDL);
+ lease_dereference (&lease, MDL);
+ }
+ }
+
+ /* If we get to here without finding a lease, no valid key was
+ specified. */
+ if (!*lp)
+ return DHCP_R_NOKEYS;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_lease_create (omapi_object_t **lp,
+ omapi_object_t *id)
+{
+ return ISC_R_NOTIMPLEMENTED;
+}
+
+isc_result_t dhcp_lease_remove (omapi_object_t *lp,
+ omapi_object_t *id)
+{
+ return ISC_R_NOTIMPLEMENTED;
+}
+
+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;
+
+ if (h -> type != dhcp_type_host)
+ return DHCP_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 && (value -> type == omapi_datatype_data ||
+ value -> type == omapi_datatype_string)) {
+ host -> name = dmalloc (value -> u.buffer.len + 1,
+ MDL);
+ 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 DHCP_R_INVALIDARG;
+ return ISC_R_SUCCESS;
+ }
+
+ if (!omapi_ds_strcmp (name, "group")) {
+ if (value && (value -> type == omapi_datatype_data ||
+ value -> type == omapi_datatype_string)) {
+ struct group_object *group;
+ group = (struct group_object *)0;
+ group_hash_lookup (&group, group_name_hash,
+ (char *)value -> u.buffer.value,
+ value -> u.buffer.len, MDL);
+ if (!group || (group -> flags & GROUP_OBJECT_DELETED))
+ return ISC_R_NOTFOUND;
+ if (host -> group)
+ group_dereference (&host -> group, MDL);
+ group_reference (&host -> group, group -> group, MDL);
+ if (host -> named_group)
+ group_object_dereference (&host -> named_group,
+ MDL);
+ group_object_reference (&host -> named_group,
+ group, MDL);
+ group_object_dereference (&group, MDL);
+ } else
+ return DHCP_R_INVALIDARG;
+ return ISC_R_SUCCESS;
+ }
+
+ if (!omapi_ds_strcmp (name, "hardware-address")) {
+ if (host -> interface.hlen)
+ return ISC_R_EXISTS;
+ if (value && (value -> type == omapi_datatype_data ||
+ value -> type == omapi_datatype_string)) {
+ if (value -> u.buffer.len >
+ (sizeof host -> interface.hbuf) - 1)
+ return DHCP_R_INVALIDARG;
+ memcpy (&host -> interface.hbuf [1],
+ value -> u.buffer.value,
+ value -> u.buffer.len);
+ host -> interface.hlen = value -> u.buffer.len + 1;
+ } else
+ return DHCP_R_INVALIDARG;
+ return ISC_R_SUCCESS;
+ }
+
+ if (!omapi_ds_strcmp (name, "hardware-type")) {
+ int type;
+ if (value && (value -> type == omapi_datatype_data &&
+ value -> u.buffer.len == sizeof type)) {
+ if (value -> u.buffer.len > sizeof type)
+ return DHCP_R_INVALIDARG;
+ memcpy (&type,
+ value -> u.buffer.value,
+ value -> u.buffer.len);
+ type = ntohl (type);
+ } else if (value -> type == omapi_datatype_int)
+ type = value -> u.integer;
+ else
+ return DHCP_R_INVALIDARG;
+ host -> interface.hbuf [0] = type;
+ return ISC_R_SUCCESS;
+ }
+
+ if (!omapi_ds_strcmp (name, "dhcp-client-identifier")) {
+ if (host -> client_identifier.data)
+ return ISC_R_EXISTS;
+ if (value && (value -> type == omapi_datatype_data ||
+ value -> type == omapi_datatype_string)) {
+ if (!buffer_allocate (&host -> client_identifier.buffer,
+ value -> u.buffer.len, MDL))
+ return ISC_R_NOMEMORY;
+ host -> client_identifier.data =
+ &host -> client_identifier.buffer -> data [0];
+ memcpy (host -> client_identifier.buffer -> data,
+ value -> u.buffer.value,
+ value -> u.buffer.len);
+ host -> client_identifier.len = value -> u.buffer.len;
+ } else
+ return DHCP_R_INVALIDARG;
+ return ISC_R_SUCCESS;
+ }
+
+ if (!omapi_ds_strcmp (name, "ip-address")) {
+ if (host -> fixed_addr)
+ option_cache_dereference (&host -> fixed_addr, MDL);
+ if (!value)
+ return ISC_R_SUCCESS;
+ if (value && (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, MDL))
+ return ISC_R_NOMEMORY;
+ ds.data = (&ds.buffer -> data [0]);
+ memcpy (ds.buffer -> data,
+ value -> u.buffer.value, ds.len);
+ if (!option_cache (&host -> fixed_addr,
+ &ds, (struct expression *)0,
+ (struct option *)0, MDL)) {
+ data_string_forget (&ds, MDL);
+ return ISC_R_NOMEMORY;
+ }
+ data_string_forget (&ds, MDL);
+ } else
+ return DHCP_R_INVALIDARG;
+ return ISC_R_SUCCESS;
+ }
+
+ if (!omapi_ds_strcmp (name, "statements")) {
+ if (!host -> group) {
+ if (!clone_group (&host -> group, root_group, MDL))
+ return ISC_R_NOMEMORY;
+ } else {
+ if (host -> group -> statements &&
+ (!host -> named_group ||
+ host -> group != host -> named_group -> group) &&
+ host -> group != root_group)
+ return ISC_R_EXISTS;
+ if (!clone_group (&host -> group, host -> group, MDL))
+ return ISC_R_NOMEMORY;
+ }
+ if (!host -> group)
+ return ISC_R_NOMEMORY;
+ if (value && (value -> type == omapi_datatype_data ||
+ value -> type == omapi_datatype_string)) {
+ struct parse *parse;
+ int lose = 0;
+ parse = (struct parse *)0;
+ status = new_parse(&parse, -1,
+ (char *) value->u.buffer.value,
+ value->u.buffer.len,
+ "network client", 0);
+ if (status != ISC_R_SUCCESS || parse == NULL)
+ return status;
+
+ if (!(parse_executable_statements
+ (&host -> group -> statements, parse, &lose,
+ context_any))) {
+ end_parse (&parse);
+ return DHCP_R_BADPARSE;
+ }
+ end_parse (&parse);
+ } else
+ return DHCP_R_INVALIDARG;
+ return ISC_R_SUCCESS;
+ }
+
+ /* The "known" flag isn't supported in the database yet, but it's
+ legitimate. */
+ if (!omapi_ds_strcmp (name, "known")) {
+ 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 == DHCP_R_UNCHANGED)
+ return status;
+ }
+
+ return DHCP_R_UNKNOWNATTRIBUTE;
+}
+
+
+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 DHCP_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 client_state *)0,
+ (struct option_state *)0,
+ (struct option_state *)0,
+ &global_scope,
+ host -> fixed_addr, MDL)) {
+ status = omapi_make_const_value (value, name,
+ ip_addrs.data,
+ ip_addrs.len, MDL);
+ data_string_forget (&ip_addrs, MDL);
+ 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,
+ MDL);
+ }
+
+ if (!omapi_ds_strcmp (name, "name"))
+ return omapi_make_string_value (value, name, host -> name,
+ MDL);
+
+ if (!omapi_ds_strcmp (name, "hardware-address")) {
+ if (!host -> interface.hlen)
+ return ISC_R_NOTFOUND;
+ return (omapi_make_const_value
+ (value, name, &host -> interface.hbuf [1],
+ (unsigned long)(host -> interface.hlen - 1), MDL));
+ }
+
+ if (!omapi_ds_strcmp (name, "hardware-type")) {
+ if (!host -> interface.hlen)
+ return ISC_R_NOTFOUND;
+ return omapi_make_int_value (value, name,
+ host -> interface.hbuf [0], MDL);
+ }
+
+ /* 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 DHCP_R_UNKNOWNATTRIBUTE;
+}
+
+isc_result_t dhcp_host_destroy (omapi_object_t *h, const char *file, int line)
+{
+ struct host_decl *host;
+
+ if (h -> type != dhcp_type_host)
+ return DHCP_R_INVALIDARG;
+ host = (struct host_decl *)h;
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ if (host -> n_ipaddr)
+ host_dereference (&host -> n_ipaddr, file, line);
+ if (host -> n_dynamic)
+ host_dereference (&host -> n_dynamic, file, line);
+ if (host -> name) {
+ dfree (host -> name, file, line);
+ host -> name = (char *)0;
+ }
+ data_string_forget (&host -> client_identifier, file, line);
+ if (host -> fixed_addr)
+ option_cache_dereference (&host -> fixed_addr, file, line);
+ if (host -> group)
+ group_dereference (&host -> group, file, line);
+ if (host -> named_group)
+ omapi_object_dereference ((omapi_object_t **)
+ &host -> named_group, file, line);
+ data_string_forget (&host -> auth_key_id, file, line);
+#endif
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_host_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ struct host_decl *host;
+ isc_result_t status;
+ int updatep = 0;
+
+ if (h -> type != dhcp_type_host)
+ return DHCP_R_INVALIDARG;
+ host = (struct host_decl *)h;
+
+ if (!strcmp (name, "updated")) {
+ /* There must be a client identifier of some sort. */
+ if (host -> interface.hlen == 0 &&
+ !host -> client_identifier.len)
+ return DHCP_R_INVALIDARG;
+
+ if (!host -> name) {
+ char hnbuf [64];
+ sprintf (hnbuf, "nh%08lx%08lx",
+ (unsigned long)cur_time, (unsigned long)host);
+ host -> name = dmalloc (strlen (hnbuf) + 1, MDL);
+ if (!host -> name)
+ return ISC_R_NOMEMORY;
+ strcpy (host -> name, hnbuf);
+ }
+
+#ifdef DEBUG_OMAPI
+ log_debug ("OMAPI added host %s", host -> name);
+#endif
+ status = enter_host (host, 1, 1);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ updatep = 1;
+ }
+
+ /* Try to find some inner object that can take the value. */
+ if (h -> inner && h -> inner -> type -> signal_handler) {
+ status = ((*(h -> inner -> type -> signal_handler))
+ (h -> inner, name, ap));
+ if (status == ISC_R_SUCCESS)
+ return status;
+ }
+ if (updatep)
+ return ISC_R_SUCCESS;
+ 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 DHCP_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 client_state *)0,
+ (struct option_state *)0,
+ (struct option_state *)0,
+ &global_scope,
+ host -> fixed_addr, MDL)) {
+ 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_copyin
+ (c,
+ host -> client_identifier.data,
+ host -> client_identifier.len));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+
+ if (host -> name) {
+ 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;
+ }
+
+ if (host -> interface.hlen) {
+ status = omapi_connection_put_name (c, "hardware-address");
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = (omapi_connection_put_uint32
+ (c, (unsigned long)(host -> interface.hlen - 1)));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = (omapi_connection_copyin
+ (c, &host -> interface.hbuf [1],
+ (unsigned long)(host -> interface.hlen - 1)));
+ 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.hbuf [0]));
+ 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;
+
+ if (!ref)
+ return DHCP_R_NOKEYS;
+
+ /* 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, MDL);
+ 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, MDL);
+ return DHCP_R_INVALIDARG;
+ }
+ if (((struct host_decl *)(*lp)) -> flags & HOST_DECL_DELETED) {
+ omapi_object_dereference (lp, MDL);
+ }
+ }
+
+ /* Now look for a client identifier. */
+ status = omapi_get_value_str (ref, id, "dhcp-client-identifier", &tv);
+ if (status == ISC_R_SUCCESS) {
+ host = (struct host_decl *)0;
+ host_hash_lookup (&host, host_uid_hash,
+ tv -> value -> u.buffer.value,
+ tv -> value -> u.buffer.len, MDL);
+ omapi_value_dereference (&tv, MDL);
+
+ if (*lp && *lp != (omapi_object_t *)host) {
+ omapi_object_dereference (lp, MDL);
+ if (host)
+ host_dereference (&host, MDL);
+ return DHCP_R_KEYCONFLICT;
+ } else if (!host || (host -> flags & HOST_DECL_DELETED)) {
+ if (*lp)
+ omapi_object_dereference (lp, MDL);
+ if (host)
+ host_dereference (&host, MDL);
+ return ISC_R_NOTFOUND;
+ } else if (!*lp) {
+ /* XXX fix so that hash lookup itself creates
+ XXX the reference. */
+ omapi_object_reference (lp,
+ (omapi_object_t *)host, MDL);
+ host_dereference (&host, MDL);
+ }
+ }
+
+ /* Now look for a hardware address. */
+ status = omapi_get_value_str (ref, id, "hardware-address", &tv);
+ if (status == ISC_R_SUCCESS) {
+ unsigned char *haddr;
+ unsigned int len;
+
+ len = tv -> value -> u.buffer.len + 1;
+ haddr = dmalloc (len, MDL);
+ if (!haddr) {
+ omapi_value_dereference (&tv, MDL);
+ return ISC_R_NOMEMORY;
+ }
+
+ memcpy (haddr + 1, tv -> value -> u.buffer.value, len - 1);
+ omapi_value_dereference (&tv, MDL);
+
+ status = omapi_get_value_str (ref, id, "hardware-type", &tv);
+ if (status == ISC_R_SUCCESS) {
+ if (tv -> value -> type == omapi_datatype_data) {
+ if ((tv -> value -> u.buffer.len != 4) ||
+ (tv -> value -> u.buffer.value[0] != 0) ||
+ (tv -> value -> u.buffer.value[1] != 0) ||
+ (tv -> value -> u.buffer.value[2] != 0)) {
+ omapi_value_dereference (&tv, MDL);
+ dfree (haddr, MDL);
+ return DHCP_R_INVALIDARG;
+ }
+
+ haddr[0] = tv -> value -> u.buffer.value[3];
+ } else if (tv -> value -> type == omapi_datatype_int) {
+ haddr[0] = (unsigned char)
+ tv -> value -> u.integer;
+ } else {
+ omapi_value_dereference (&tv, MDL);
+ dfree (haddr, MDL);
+ return DHCP_R_INVALIDARG;
+ }
+
+ omapi_value_dereference (&tv, MDL);
+ } else {
+ /* If no hardware-type is specified, default to
+ ethernet. This may or may not be a good idea,
+ but Telus is currently relying on this behavior.
+ - DPN */
+ haddr[0] = HTYPE_ETHER;
+ }
+
+ host = (struct host_decl *)0;
+ host_hash_lookup (&host, host_hw_addr_hash, haddr, len, MDL);
+ dfree (haddr, MDL);
+
+ if (*lp && *lp != (omapi_object_t *)host) {
+ omapi_object_dereference (lp, MDL);
+ if (host)
+ host_dereference (&host, MDL);
+ return DHCP_R_KEYCONFLICT;
+ } else if (!host || (host -> flags & HOST_DECL_DELETED)) {
+ if (*lp)
+ omapi_object_dereference (lp, MDL);
+ if (host)
+ host_dereference (&host, MDL);
+ return ISC_R_NOTFOUND;
+ } else if (!*lp) {
+ /* XXX fix so that hash lookup itself creates
+ XXX the reference. */
+ omapi_object_reference (lp,
+ (omapi_object_t *)host, MDL);
+ host_dereference (&host, MDL);
+ }
+ }
+
+ /* Now look for an ip address. */
+ status = omapi_get_value_str (ref, id, "ip-address", &tv);
+ if (status == ISC_R_SUCCESS) {
+ struct lease *l;
+
+ /* first find the lease for this ip address */
+ l = (struct lease *)0;
+ lease_ip_hash_lookup(&l, lease_ip_addr_hash,
+ tv->value->u.buffer.value,
+ tv->value->u.buffer.len, MDL);
+ omapi_value_dereference (&tv, MDL);
+
+ if (!l && !*lp)
+ return ISC_R_NOTFOUND;
+
+ if (l) {
+ /* now use that to get a host */
+ host = (struct host_decl *)0;
+ host_hash_lookup (&host, host_hw_addr_hash,
+ l -> hardware_addr.hbuf,
+ l -> hardware_addr.hlen, MDL);
+
+ if (host && *lp && *lp != (omapi_object_t *)host) {
+ omapi_object_dereference (lp, MDL);
+ if (host)
+ host_dereference (&host, MDL);
+ return DHCP_R_KEYCONFLICT;
+ } else if (!host || (host -> flags &
+ HOST_DECL_DELETED)) {
+ if (host)
+ host_dereference (&host, MDL);
+ if (!*lp)
+ return ISC_R_NOTFOUND;
+ } else if (!*lp) {
+ /* XXX fix so that hash lookup itself creates
+ XXX the reference. */
+ omapi_object_reference (lp, (omapi_object_t *)host,
+ MDL);
+ host_dereference (&host, MDL);
+ }
+ lease_dereference (&l, MDL);
+ }
+ }
+
+ /* Now look for a name. */
+ status = omapi_get_value_str (ref, id, "name", &tv);
+ if (status == ISC_R_SUCCESS) {
+ host = (struct host_decl *)0;
+ host_hash_lookup (&host, host_name_hash,
+ tv -> value -> u.buffer.value,
+ tv -> value -> u.buffer.len, MDL);
+ omapi_value_dereference (&tv, MDL);
+
+ if (*lp && *lp != (omapi_object_t *)host) {
+ omapi_object_dereference (lp, MDL);
+ if (host)
+ host_dereference (&host, MDL);
+ return DHCP_R_KEYCONFLICT;
+ } else if (!host || (host -> flags & HOST_DECL_DELETED)) {
+ if (host)
+ host_dereference (&host, MDL);
+ return ISC_R_NOTFOUND;
+ } else if (!*lp) {
+ /* XXX fix so that hash lookup itself creates
+ XXX the reference. */
+ omapi_object_reference (lp,
+ (omapi_object_t *)host, MDL);
+ host_dereference (&host, MDL);
+ }
+ }
+
+ /* If we get to here without finding a host, no valid key was
+ specified. */
+ if (!*lp)
+ return DHCP_R_NOKEYS;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_host_create (omapi_object_t **lp,
+ omapi_object_t *id)
+{
+ struct host_decl *hp;
+ isc_result_t status;
+ hp = (struct host_decl *)0;
+ status = host_allocate (&hp, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ group_reference (&hp -> group, root_group, MDL);
+ hp -> flags = HOST_DECL_DYNAMIC;
+ status = omapi_object_reference (lp, (omapi_object_t *)hp, MDL);
+ host_dereference (&hp, MDL);
+ return status;
+}
+
+isc_result_t dhcp_host_remove (omapi_object_t *lp,
+ omapi_object_t *id)
+{
+ struct host_decl *hp;
+ if (lp -> type != dhcp_type_host)
+ return DHCP_R_INVALIDARG;
+ hp = (struct host_decl *)lp;
+
+#ifdef DEBUG_OMAPI
+ log_debug ("OMAPI delete host %s", hp -> name);
+#endif
+ delete_host (hp, 1);
+ return ISC_R_SUCCESS;
+}
+
+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;
+
+ if (h -> type != dhcp_type_pool)
+ return DHCP_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 == DHCP_R_UNCHANGED)
+ return status;
+ }
+
+ return DHCP_R_UNKNOWNATTRIBUTE;
+}
+
+
+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 DHCP_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 DHCP_R_UNKNOWNATTRIBUTE;
+}
+
+isc_result_t dhcp_pool_destroy (omapi_object_t *h, const char *file, int line)
+{
+ struct pool *pool;
+#if defined (DEBUG_MEMORY_LEAKAGE) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ struct permit *pc, *pn;
+#endif
+
+ if (h -> type != dhcp_type_pool)
+ return DHCP_R_INVALIDARG;
+ pool = (struct pool *)h;
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ if (pool -> next)
+ pool_dereference (&pool -> next, file, line);
+ if (pool -> group)
+ group_dereference (&pool -> group, file, line);
+ if (pool -> shared_network)
+ shared_network_dereference (&pool -> shared_network, file, line);
+ if (pool -> active)
+ lease_dereference (&pool -> active, file, line);
+ if (pool -> expired)
+ lease_dereference (&pool -> expired, file, line);
+ if (pool -> free)
+ lease_dereference (&pool -> free, file, line);
+ if (pool -> backup)
+ lease_dereference (&pool -> backup, file, line);
+ if (pool -> abandoned)
+ lease_dereference (&pool -> abandoned, file, line);
+#if defined (FAILOVER_PROTOCOL)
+ if (pool -> failover_peer)
+ dhcp_failover_state_dereference (&pool -> failover_peer,
+ file, line);
+#endif
+ for (pc = pool -> permit_list; pc; pc = pn) {
+ pn = pc -> next;
+ free_permit (pc, file, line);
+ }
+ pool -> permit_list = (struct permit *)0;
+
+ for (pc = pool -> prohibit_list; pc; pc = pn) {
+ pn = pc -> next;
+ free_permit (pc, file, line);
+ }
+ pool -> prohibit_list = (struct permit *)0;
+#endif
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_pool_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ struct pool *pool;
+ isc_result_t status;
+ int updatep = 0;
+
+ if (h -> type != dhcp_type_pool)
+ return DHCP_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 -> signal_handler) {
+ status = ((*(h -> inner -> type -> signal_handler))
+ (h -> inner, name, ap));
+ if (status == ISC_R_SUCCESS)
+ return status;
+ }
+ if (updatep)
+ return ISC_R_SUCCESS;
+ 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 DHCP_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)
+{
+ /* Can't look up pools yet. */
+
+ /* If we get to here without finding a pool, no valid key was
+ specified. */
+ if (!*lp)
+ return DHCP_R_NOKEYS;
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_pool_create (omapi_object_t **lp,
+ omapi_object_t *id)
+{
+ return ISC_R_NOTIMPLEMENTED;
+}
+
+isc_result_t dhcp_pool_remove (omapi_object_t *lp,
+ omapi_object_t *id)
+{
+ return ISC_R_NOTIMPLEMENTED;
+}
+
+static isc_result_t
+class_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ struct class *class;
+ struct class *superclass = 0;
+ isc_result_t status;
+ int issubclass = (h -> type == dhcp_type_subclass);
+
+ class = (struct class *)h;
+
+ if (!omapi_ds_strcmp(name, "name")) {
+ char *tname;
+
+ if (class->name)
+ return ISC_R_EXISTS;
+
+ if ((tname = dmalloc(value->u.buffer.len + 1, MDL)) == NULL) {
+ return ISC_R_NOMEMORY;
+ }
+
+ /* tname is null terminated from dmalloc() */
+ memcpy(tname, value->u.buffer.value, value->u.buffer.len);
+
+ if (issubclass) {
+ status = find_class(&superclass, tname, MDL);
+ dfree(tname, MDL);
+
+ if (status == ISC_R_NOTFOUND)
+ return status;
+
+ if (class->superclass != NULL)
+ class_dereference(&class->superclass, MDL);
+
+ class_reference(&class->superclass, superclass, MDL);
+ } else if (value -> type == omapi_datatype_data ||
+ value -> type == omapi_datatype_string) {
+ class->name = dmalloc(value->u.buffer.len + 1, MDL);
+ if (!class->name)
+ return ISC_R_NOMEMORY;
+
+ /* class->name is null-terminated from dmalloc() */
+ memcpy(class->name, value->u.buffer.value,
+ value->u.buffer.len);
+ } else
+ return DHCP_R_INVALIDARG;
+
+ return ISC_R_SUCCESS;
+ }
+
+
+ if (issubclass && !omapi_ds_strcmp(name, "hashstring")) {
+ if (class->hash_string.data)
+ return ISC_R_EXISTS;
+
+ if (value->type == omapi_datatype_data ||
+ value->type == omapi_datatype_string) {
+ if (!buffer_allocate(&class->hash_string.buffer,
+ value->u.buffer.len, MDL))
+ return ISC_R_NOMEMORY;
+ class->hash_string.data =
+ class->hash_string.buffer->data;
+ memcpy(class->hash_string.buffer->data,
+ value->u.buffer.value, value->u.buffer.len);
+ class->hash_string.len = value->u.buffer.len;
+ } else
+ return DHCP_R_INVALIDARG;
+
+ return ISC_R_SUCCESS;
+ }
+
+ if (!omapi_ds_strcmp(name, "group")) {
+ if (value->type == omapi_datatype_data ||
+ value->type == omapi_datatype_string) {
+ struct group_object *group = NULL;
+
+ group_hash_lookup(&group, group_name_hash,
+ (char *)value->u.buffer.value,
+ value->u.buffer.len, MDL);
+ if (!group || (group->flags & GROUP_OBJECT_DELETED))
+ return ISC_R_NOTFOUND;
+ if (class->group)
+ group_dereference(&class->group, MDL);
+ group_reference(&class->group, group->group, MDL);
+ group_object_dereference(&group, MDL);
+ } else
+ return DHCP_R_INVALIDARG;
+
+ return ISC_R_SUCCESS;
+ }
+
+
+ /* note we do not support full expressions via omapi because the
+ expressions parser needs to be re-done to support parsing from
+ strings and not just files. */
+
+ if (!omapi_ds_strcmp(name, "match")) {
+ if (value->type == omapi_datatype_data ||
+ value->type == omapi_datatype_string) {
+ unsigned minlen = (value->u.buffer.len > 8 ?
+ 8 : value->u.buffer.len);
+
+ if (!strncmp("hardware",
+ (char *)value->u.buffer.value, minlen))
+ {
+ if (!expression_allocate(&class->submatch, MDL))
+ return ISC_R_NOMEMORY;
+
+ class->submatch->op = expr_hardware;
+ } else
+ return DHCP_R_INVALIDARG;
+ } else
+ return DHCP_R_INVALIDARG;
+
+ return ISC_R_SUCCESS;
+ }
+
+
+ if (!omapi_ds_strcmp(name, "option")) {
+ if (value->type == omapi_datatype_data ||
+ value->type == omapi_datatype_string) {
+ /* XXXJAB support 'options' here. */
+ /* XXXJAB specifically 'bootfile-name' */
+ return DHCP_R_INVALIDARG; /* XXX tmp */
+ } else
+ return DHCP_R_INVALIDARG;
+
+ /*
+ * Currently no way to get here, if we update the above
+ * code so that we do get here this return needs to be
+ * uncommented.
+ * 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 == DHCP_R_UNCHANGED)
+ return status;
+ }
+
+ return DHCP_R_UNKNOWNATTRIBUTE;
+}
+
+
+
+isc_result_t dhcp_class_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ if (h -> type != dhcp_type_class)
+ return DHCP_R_INVALIDARG;
+
+ return class_set_value(h, id, name, value);
+}
+
+isc_result_t dhcp_class_get_value (omapi_object_t *h, omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ struct class *class;
+ isc_result_t status;
+
+ if (h -> type != dhcp_type_class)
+ return DHCP_R_INVALIDARG;
+ class = (struct class *)h;
+
+ if (!omapi_ds_strcmp (name, "name"))
+ return omapi_make_string_value (value, name, class -> name,
+ MDL);
+
+ /* 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 DHCP_R_UNKNOWNATTRIBUTE;
+}
+
+isc_result_t dhcp_class_destroy (omapi_object_t *h, const char *file, int line)
+{
+ struct class *class;
+
+ if (h -> type != dhcp_type_class && h -> type != dhcp_type_subclass)
+ return DHCP_R_INVALIDARG;
+ class = (struct class *)h;
+
+#if defined (DEBUG_MEMORY_LEAKAGE) || \
+ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
+ if (class -> nic)
+ class_dereference (&class -> nic, file, line);
+ if (class -> superclass)
+ class_dereference (&class -> superclass, file, line);
+ if (class -> name) {
+ dfree (class -> name, file, line);
+ class -> name = (char *)0;
+ }
+ if (class -> billed_leases) {
+ int i;
+ for (i = 0; i < class -> lease_limit; i++) {
+ if (class -> billed_leases [i]) {
+ lease_dereference (&class -> billed_leases [i],
+ file, line);
+ }
+ }
+ dfree (class -> billed_leases, file, line);
+ class -> billed_leases = (struct lease **)0;
+ }
+ if (class -> hash) {
+ class_free_hash_table (&class -> hash, file, line);
+ class -> hash = (class_hash_t *)0;
+ }
+ data_string_forget (&class -> hash_string, file, line);
+
+ if (class -> expr)
+ expression_dereference (&class -> expr, file, line);
+ if (class -> submatch)
+ expression_dereference (&class -> submatch, file, line);
+ if (class -> group)
+ group_dereference (&class -> group, file, line);
+ if (class -> statements)
+ executable_statement_dereference (&class -> statements,
+ file, line);
+ if (class -> superclass)
+ class_dereference (&class -> superclass, file, line);
+#endif
+
+ return ISC_R_SUCCESS;
+}
+
+static isc_result_t
+class_signal_handler(omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ struct class *class = (struct class *)h;
+ isc_result_t status;
+ int updatep = 0;
+ int issubclass;
+
+ issubclass = (h -> type == dhcp_type_subclass);
+
+ if (!strcmp (name, "updated")) {
+
+ if (!issubclass) {
+ if (class -> name == 0 || strlen(class -> name) == 0) {
+ return DHCP_R_INVALIDARG;
+ }
+ } else {
+ if (class -> superclass == 0) {
+ return DHCP_R_INVALIDARG; /* didn't give name */
+ }
+
+ if (class -> hash_string.data == NULL) {
+ return DHCP_R_INVALIDARG;
+ }
+ }
+
+
+ if (issubclass) {
+ if (!class -> superclass -> hash)
+ class_new_hash(&class->superclass->hash,
+ SCLASS_HASH_SIZE, MDL);
+
+ add_hash (class -> superclass -> hash,
+ class -> hash_string.data,
+ class -> hash_string.len,
+ (void *)class, MDL);
+ }
+
+
+#ifdef DEBUG_OMAPI
+ if (issubclass) {
+ log_debug ("OMAPI added subclass %s",
+ class -> superclass -> name);
+ } else {
+ log_debug ("OMAPI added class %s", class -> name);
+ }
+#endif
+
+ status = enter_class (class, 1, 1);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ updatep = 1;
+ }
+
+ /* Try to find some inner object that can take the value. */
+ if (h -> inner && h -> inner -> type -> signal_handler) {
+ status = ((*(h -> inner -> type -> signal_handler))
+ (h -> inner, name, ap));
+ if (status == ISC_R_SUCCESS)
+ return status;
+ }
+
+ if (updatep)
+ return ISC_R_SUCCESS;
+
+ return ISC_R_NOTFOUND;
+}
+
+
+isc_result_t dhcp_class_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ if (h -> type != dhcp_type_class)
+ return DHCP_R_INVALIDARG;
+
+ return class_signal_handler(h, name, ap);
+}
+
+isc_result_t dhcp_class_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *h)
+{
+ struct class *class;
+ isc_result_t status;
+
+ if (h -> type != dhcp_type_class)
+ return DHCP_R_INVALIDARG;
+ class = (struct class *)h;
+
+ /* Can't stuff class 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;
+}
+
+static isc_result_t class_lookup (omapi_object_t **lp,
+ omapi_object_t *id, omapi_object_t *ref,
+ omapi_object_type_t *typewanted)
+{
+ omapi_value_t *nv = (omapi_value_t *)0;
+ omapi_value_t *hv = (omapi_value_t *)0;
+ isc_result_t status;
+ struct class *class = 0;
+ struct class *subclass = 0;
+
+ *lp = NULL;
+
+ /* see if we have a name */
+ status = omapi_get_value_str (ref, id, "name", &nv);
+ if (status == ISC_R_SUCCESS) {
+ char *name = dmalloc(nv -> value -> u.buffer.len + 1, MDL);
+ memcpy (name,
+ nv -> value -> u.buffer.value,
+ nv -> value -> u.buffer.len);
+
+ omapi_value_dereference (&nv, MDL);
+
+ find_class(&class, name, MDL);
+
+ dfree(name, MDL);
+
+ if (class == NULL) {
+ return ISC_R_NOTFOUND;
+ }
+
+ if (typewanted == dhcp_type_subclass) {
+ status = omapi_get_value_str (ref, id,
+ "hashstring", &hv);
+ if (status != ISC_R_SUCCESS) {
+ class_dereference(&class, MDL);
+ return DHCP_R_NOKEYS;
+ }
+
+ if (hv -> value -> type != omapi_datatype_data &&
+ hv -> value -> type != omapi_datatype_string) {
+ class_dereference(&class, MDL);
+ omapi_value_dereference (&hv, MDL);
+ return DHCP_R_NOKEYS;
+ }
+
+ class_hash_lookup (&subclass, class -> hash,
+ (const char *)
+ hv -> value -> u.buffer.value,
+ hv -> value -> u.buffer.len, MDL);
+
+ omapi_value_dereference (&hv, MDL);
+
+ class_dereference(&class, MDL);
+
+ if (subclass == NULL) {
+ return ISC_R_NOTFOUND;
+ }
+
+ class_reference(&class, subclass, MDL);
+ class_dereference(&subclass, MDL);
+ }
+
+
+ /* Don't return the object if the type is wrong. */
+ if (class -> type != typewanted) {
+ class_dereference (&class, MDL);
+ return DHCP_R_INVALIDARG;
+ }
+
+ if (class -> flags & CLASS_DECL_DELETED) {
+ class_dereference (&class, MDL);
+ }
+
+ omapi_object_reference(lp, (omapi_object_t *)class, MDL);
+
+ return ISC_R_SUCCESS;
+ }
+
+ return DHCP_R_NOKEYS;
+}
+
+
+isc_result_t dhcp_class_lookup (omapi_object_t **lp,
+ omapi_object_t *id, omapi_object_t *ref)
+{
+ return class_lookup(lp, id, ref, dhcp_type_class);
+}
+
+isc_result_t dhcp_class_create (omapi_object_t **lp,
+ omapi_object_t *id)
+{
+ struct class *cp = 0;
+ isc_result_t status;
+
+ status = class_allocate(&cp, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ group_reference (&cp -> group, root_group, MDL);
+ cp -> flags = CLASS_DECL_DYNAMIC;
+ status = omapi_object_reference (lp, (omapi_object_t *)cp, MDL);
+ class_dereference (&cp, MDL);
+ return status;
+}
+
+isc_result_t dhcp_class_remove (omapi_object_t *lp,
+ omapi_object_t *id)
+{
+ struct class *cp;
+ if (lp -> type != dhcp_type_class)
+ return DHCP_R_INVALIDARG;
+ cp = (struct class *)lp;
+
+#ifdef DEBUG_OMAPI
+ log_debug ("OMAPI delete class %s", cp -> name);
+#endif
+
+ delete_class (cp, 1);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t dhcp_subclass_set_value (omapi_object_t *h,
+ omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ if (h -> type != dhcp_type_subclass)
+ return DHCP_R_INVALIDARG;
+
+ return class_set_value(h, id, name, value);
+}
+
+
+isc_result_t dhcp_subclass_get_value (omapi_object_t *h, omapi_object_t *id,
+ omapi_data_string_t *name,
+ omapi_value_t **value)
+{
+ struct class *subclass;
+ isc_result_t status;
+
+ if (h -> type != dhcp_type_class)
+ return DHCP_R_INVALIDARG;
+ subclass = (struct class *)h;
+ if (subclass -> name != 0)
+ return DHCP_R_INVALIDARG;
+
+ /* XXXJAB 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 DHCP_R_UNKNOWNATTRIBUTE;
+}
+
+isc_result_t dhcp_subclass_signal_handler (omapi_object_t *h,
+ const char *name, va_list ap)
+{
+ if (h -> type != dhcp_type_subclass)
+ return DHCP_R_INVALIDARG;
+
+ return class_signal_handler(h, name, ap);
+}
+
+
+isc_result_t dhcp_subclass_stuff_values (omapi_object_t *c,
+ omapi_object_t *id,
+ omapi_object_t *h)
+{
+ struct class *subclass;
+ isc_result_t status;
+
+ if (h -> type != dhcp_type_class)
+ return DHCP_R_INVALIDARG;
+ subclass = (struct class *)h;
+ if (subclass -> name != 0)
+ return DHCP_R_INVALIDARG;
+
+
+ /* Can't stuff subclass 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_subclass_lookup (omapi_object_t **lp,
+ omapi_object_t *id, omapi_object_t *ref)
+{
+ return class_lookup(lp, id, ref, dhcp_type_subclass);
+}
+
+
+
+
+isc_result_t dhcp_subclass_create (omapi_object_t **lp,
+ omapi_object_t *id)
+{
+ struct class *cp = 0;
+ isc_result_t status;
+
+/*
+ * XXX
+ * NOTE: subclasses and classes have the same internal type, which makes it
+ * difficult to tell them apart. Specifically, in this function we need to
+ * create a class object (because there is no such thing as a subclass
+ * object), but one field of the class object is the type (which has the
+ * value dhcp_type_class), and it is from here that all the other omapi
+ * functions are accessed. So, even though there's a whole suite of
+ * subclass functions registered, they won't get used. Now we could change
+ * the type pointer after creating the class object, but I'm not certain
+ * that won't break something else.
+ */
+
+ status = subclass_allocate(&cp, MDL);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ group_reference (&cp -> group, root_group, MDL);
+
+ cp -> flags = CLASS_DECL_DYNAMIC;
+
+ status = omapi_object_reference (lp, (omapi_object_t *)cp, MDL);
+ subclass_dereference (&cp, MDL);
+ return status;
+}
+
+isc_result_t dhcp_subclass_remove (omapi_object_t *lp,
+ omapi_object_t *id)
+{
+#if 1
+
+ log_fatal("calling dhcp_subclass_set_value");
+ /* this should never be called see dhcp_subclass_create for why */
+
+#else
+
+ struct class *cp;
+ if (lp -> type != dhcp_type_subclass)
+ return DHCP_R_INVALIDARG;
+ cp = (struct class *)lp;
+
+#ifdef DEBUG_OMAPI
+ log_debug ("OMAPI delete subclass %s", cp -> name);
+#endif
+
+ delete_class (cp, 1);
+
+#endif
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t binding_scope_set_value (struct binding_scope *scope, int createp,
+ omapi_data_string_t *name,
+ omapi_typed_data_t *value)
+{
+ struct binding *bp;
+ char *nname;
+ struct binding_value *nv;
+ nname = dmalloc (name -> len + 1, MDL);
+ if (!nname)
+ return ISC_R_NOMEMORY;
+ memcpy (nname, name -> value, name -> len);
+ nname [name -> len] = 0;
+ bp = find_binding (scope, nname);
+ if (!bp && !createp) {
+ dfree (nname, MDL);
+ return DHCP_R_UNKNOWNATTRIBUTE;
+ }
+ if (!value) {
+ dfree (nname, MDL);
+ if (!bp)
+ return DHCP_R_UNKNOWNATTRIBUTE;
+ binding_value_dereference (&bp -> value, MDL);
+ return ISC_R_SUCCESS;
+ }
+
+ nv = (struct binding_value *)0;
+ if (!binding_value_allocate (&nv, MDL)) {
+ dfree (nname, MDL);
+ return ISC_R_NOMEMORY;
+ }
+ switch (value -> type) {
+ case omapi_datatype_int:
+ nv -> type = binding_numeric;
+ nv -> value.intval = value -> u.integer;
+ break;
+
+ case omapi_datatype_string:
+ case omapi_datatype_data:
+ if (!buffer_allocate (&nv -> value.data.buffer,
+ value -> u.buffer.len, MDL)) {
+ binding_value_dereference (&nv, MDL);
+ dfree (nname, MDL);
+ return ISC_R_NOMEMORY;
+ }
+ memcpy (&nv -> value.data.buffer -> data [1],
+ value -> u.buffer.value, value -> u.buffer.len);
+ nv -> value.data.len = value -> u.buffer.len;
+ break;
+
+ case omapi_datatype_object:
+ binding_value_dereference (&nv, MDL);
+ dfree (nname, MDL);
+ return DHCP_R_INVALIDARG;
+ }
+
+ if (!bp) {
+ bp = dmalloc (sizeof *bp, MDL);
+ if (!bp) {
+ binding_value_dereference (&nv, MDL);
+ dfree (nname, MDL);
+ return ISC_R_NOMEMORY;
+ }
+ memset (bp, 0, sizeof *bp);
+ bp -> name = nname;
+ nname = (char *)0;
+ bp -> next = scope -> bindings;
+ scope -> bindings = bp;
+ } else {
+ if (bp -> value)
+ binding_value_dereference (&bp -> value, MDL);
+ dfree (nname, MDL);
+ }
+ binding_value_reference (&bp -> value, nv, MDL);
+ binding_value_dereference (&nv, MDL);
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t binding_scope_get_value (omapi_value_t **value,
+ struct binding_scope *scope,
+ omapi_data_string_t *name)
+{
+ struct binding *bp;
+ omapi_typed_data_t *td;
+ isc_result_t status;
+ char *nname;
+ nname = dmalloc (name -> len + 1, MDL);
+ if (!nname)
+ return ISC_R_NOMEMORY;
+ memcpy (nname, name -> value, name -> len);
+ nname [name -> len] = 0;
+ bp = find_binding (scope, nname);
+ dfree (nname, MDL);
+ if (!bp)
+ return DHCP_R_UNKNOWNATTRIBUTE;
+ if (!bp -> value)
+ return DHCP_R_UNKNOWNATTRIBUTE;
+
+ switch (bp -> value -> type) {
+ case binding_boolean:
+ td = (omapi_typed_data_t *)0;
+ status = omapi_typed_data_new (MDL, &td, omapi_datatype_int,
+ bp -> value -> value.boolean);
+ break;
+
+ case binding_numeric:
+ td = (omapi_typed_data_t *)0;
+ status = omapi_typed_data_new (MDL, &td, omapi_datatype_int,
+ (int)
+ bp -> value -> value.intval);
+ break;
+
+ case binding_data:
+ td = (omapi_typed_data_t *)0;
+ status = omapi_typed_data_new (MDL, &td, omapi_datatype_data,
+ bp -> value -> value.data.len);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ memcpy (&td -> u.buffer.value [0],
+ bp -> value -> value.data.data,
+ bp -> value -> value.data.len);
+ break;
+
+ /* Can't return values for these two (yet?). */
+ case binding_dns:
+ case binding_function:
+ return DHCP_R_INVALIDARG;
+
+ default:
+ log_fatal ("Impossible case at %s:%d.", MDL);
+ return ISC_R_FAILURE;
+ }
+
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_value_new (value, MDL);
+ if (status != ISC_R_SUCCESS) {
+ omapi_typed_data_dereference (&td, MDL);
+ return status;
+ }
+
+ omapi_data_string_reference (&(*value) -> name, name, MDL);
+ omapi_typed_data_reference (&(*value) -> value, td, MDL);
+ omapi_typed_data_dereference (&td, MDL);
+
+ return ISC_R_SUCCESS;
+}
+
+isc_result_t binding_scope_stuff_values (omapi_object_t *c,
+ struct binding_scope *scope)
+{
+ struct binding *bp;
+ unsigned len;
+ isc_result_t status;
+
+ for (bp = scope -> bindings; bp; bp = bp -> next) {
+ if (bp -> value) {
+ if (bp -> value -> type == binding_dns ||
+ bp -> value -> type == binding_function)
+ continue;
+
+ /* Stuff the name. */
+ len = strlen (bp -> name);
+ status = omapi_connection_put_uint16 (c, len);
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = omapi_connection_copyin (c,
+ (unsigned char *)bp -> name,
+ len);
+ if (status != ISC_R_SUCCESS)
+ return status;
+
+ switch (bp -> value -> type) {
+ case binding_boolean:
+ status = omapi_connection_put_uint32 (c,
+ sizeof (u_int32_t));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = (omapi_connection_put_uint32
+ (c,
+ ((u_int32_t)(bp -> value -> value.boolean))));
+ break;
+
+ case binding_data:
+ status = (omapi_connection_put_uint32
+ (c, bp -> value -> value.data.len));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ if (bp -> value -> value.data.len) {
+ status = (omapi_connection_copyin
+ (c, bp -> value -> value.data.data,
+ bp -> value -> value.data.len));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ }
+ break;
+
+ case binding_numeric:
+ status = (omapi_connection_put_uint32
+ (c, sizeof (u_int32_t)));
+ if (status != ISC_R_SUCCESS)
+ return status;
+ status = (omapi_connection_put_uint32
+ (c, ((u_int32_t)
+ (bp -> value -> value.intval))));
+ break;
+
+
+ /* NOTREACHED */
+ case binding_dns:
+ case binding_function:
+ break;
+ }
+ }
+ }
+ return ISC_R_SUCCESS;
+}
+
+/* vim: set tabstop=8: */