1/*	$NetBSD: omapi.c,v 1.3 2022/04/03 01:11:00 christos Exp $	*/
2
3/* omapi.c
4
5   OMAPI object interfaces for the DHCP server. */
6
7/*
8 * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 1999-2003 by Internet Software Consortium
10 *
11 * This Source Code Form is subject to the terms of the Mozilla Public
12 * License, v. 2.0. If a copy of the MPL was not distributed with this
13 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 *   Internet Systems Consortium, Inc.
24 *   PO Box 360
25 *   Newmarket, NH 03857 USA
26 *   <info@isc.org>
27 *   https://www.isc.org/
28 *
29 */
30
31#include <sys/cdefs.h>
32__RCSID("$NetBSD: omapi.c,v 1.3 2022/04/03 01:11:00 christos Exp $");
33
34/* Many, many thanks to Brian Murrell and BCtel for this code - BCtel
35   provided the funding that resulted in this code and the entire
36   OMAPI support library being written, and Brian helped brainstorm
37   and refine the requirements.  To the extent that this code is
38   useful, you have Brian and BCtel to thank.  Any limitations in the
39   code are a result of mistakes on my part.  -- Ted Lemon */
40
41#include "dhcpd.h"
42#include <omapip/omapip_p.h>
43
44static isc_result_t class_lookup (omapi_object_t **,
45				  omapi_object_t *, omapi_object_t *,
46				  omapi_object_type_t *);
47
48static isc_result_t update_lease_flags(struct lease* lease,
49				       omapi_typed_data_t *value);
50
51omapi_object_type_t *dhcp_type_lease;
52omapi_object_type_t *dhcp_type_pool;
53omapi_object_type_t *dhcp_type_class;
54omapi_object_type_t *dhcp_type_subclass;
55omapi_object_type_t *dhcp_type_host;
56#if defined (FAILOVER_PROTOCOL)
57omapi_object_type_t *dhcp_type_failover_state;
58omapi_object_type_t *dhcp_type_failover_link;
59omapi_object_type_t *dhcp_type_failover_listener;
60#endif
61
62void dhcp_db_objects_setup ()
63{
64	isc_result_t status;
65
66	status = omapi_object_type_register (&dhcp_type_lease,
67					     "lease",
68					     dhcp_lease_set_value,
69					     dhcp_lease_get_value,
70					     dhcp_lease_destroy,
71					     dhcp_lease_signal_handler,
72					     dhcp_lease_stuff_values,
73					     dhcp_lease_lookup,
74					     dhcp_lease_create,
75					     dhcp_lease_remove,
76#if defined (COMPACT_LEASES)
77					     dhcp_lease_free,
78					     dhcp_lease_get,
79#else
80					     0, 0,
81#endif
82					     0,
83					     sizeof (struct lease),
84					     0, RC_LEASE);
85	if (status != ISC_R_SUCCESS)
86		log_fatal ("Can't register lease object type: %s",
87			   isc_result_totext (status));
88
89	status = omapi_object_type_register (&dhcp_type_class,
90					     "class",
91					     dhcp_class_set_value,
92					     dhcp_class_get_value,
93					     dhcp_class_destroy,
94					     dhcp_class_signal_handler,
95					     dhcp_class_stuff_values,
96					     dhcp_class_lookup,
97					     dhcp_class_create,
98					     dhcp_class_remove, 0, 0, 0,
99					     sizeof (struct class), 0,
100					     RC_MISC);
101	if (status != ISC_R_SUCCESS)
102		log_fatal ("Can't register class object type: %s",
103			   isc_result_totext (status));
104
105	status = omapi_object_type_register (&dhcp_type_subclass,
106					     "subclass",
107					     dhcp_subclass_set_value,
108					     dhcp_subclass_get_value,
109					     dhcp_class_destroy,
110					     dhcp_subclass_signal_handler,
111					     dhcp_subclass_stuff_values,
112					     dhcp_subclass_lookup,
113					     dhcp_subclass_create,
114					     dhcp_subclass_remove, 0, 0, 0,
115					     sizeof (struct class), 0, RC_MISC);
116	if (status != ISC_R_SUCCESS)
117		log_fatal ("Can't register subclass object type: %s",
118			   isc_result_totext (status));
119
120	status = omapi_object_type_register (&dhcp_type_pool,
121					     "pool",
122					     dhcp_pool_set_value,
123					     dhcp_pool_get_value,
124					     dhcp_pool_destroy,
125					     dhcp_pool_signal_handler,
126					     dhcp_pool_stuff_values,
127					     dhcp_pool_lookup,
128					     dhcp_pool_create,
129					     dhcp_pool_remove, 0, 0, 0,
130					     sizeof (struct pool), 0, RC_MISC);
131
132	if (status != ISC_R_SUCCESS)
133		log_fatal ("Can't register pool object type: %s",
134			   isc_result_totext (status));
135
136	status = omapi_object_type_register (&dhcp_type_host,
137					     "host",
138					     dhcp_host_set_value,
139					     dhcp_host_get_value,
140					     dhcp_host_destroy,
141					     dhcp_host_signal_handler,
142					     dhcp_host_stuff_values,
143					     dhcp_host_lookup,
144					     dhcp_host_create,
145					     dhcp_host_remove, 0, 0, 0,
146					     sizeof (struct host_decl),
147					     0, RC_MISC);
148
149	if (status != ISC_R_SUCCESS)
150		log_fatal ("Can't register host object type: %s",
151			   isc_result_totext (status));
152
153#if defined (FAILOVER_PROTOCOL)
154	status = omapi_object_type_register (&dhcp_type_failover_state,
155					     "failover-state",
156					     dhcp_failover_state_set_value,
157					     dhcp_failover_state_get_value,
158					     dhcp_failover_state_destroy,
159					     dhcp_failover_state_signal,
160					     dhcp_failover_state_stuff,
161					     dhcp_failover_state_lookup,
162					     dhcp_failover_state_create,
163					     dhcp_failover_state_remove,
164					     0, 0, 0,
165					     sizeof (dhcp_failover_state_t),
166					     0, RC_MISC);
167
168	if (status != ISC_R_SUCCESS)
169		log_fatal ("Can't register failover state object type: %s",
170			   isc_result_totext (status));
171
172	status = omapi_object_type_register (&dhcp_type_failover_link,
173					     "failover-link",
174					     dhcp_failover_link_set_value,
175					     dhcp_failover_link_get_value,
176					     dhcp_failover_link_destroy,
177					     dhcp_failover_link_signal,
178					     dhcp_failover_link_stuff_values,
179					     0, 0, 0, 0, 0, 0,
180					     sizeof (dhcp_failover_link_t), 0,
181					     RC_MISC);
182
183	if (status != ISC_R_SUCCESS)
184		log_fatal ("Can't register failover link object type: %s",
185			   isc_result_totext (status));
186
187	status = omapi_object_type_register (&dhcp_type_failover_listener,
188					     "failover-listener",
189					     dhcp_failover_listener_set_value,
190					     dhcp_failover_listener_get_value,
191					     dhcp_failover_listener_destroy,
192					     dhcp_failover_listener_signal,
193					     dhcp_failover_listener_stuff,
194					     0, 0, 0, 0, 0, 0,
195					     sizeof
196					     (dhcp_failover_listener_t), 0,
197					     RC_MISC);
198
199	if (status != ISC_R_SUCCESS)
200		log_fatal ("Can't register failover listener object type: %s",
201			   isc_result_totext (status));
202#endif /* FAILOVER_PROTOCOL */
203}
204
205isc_result_t dhcp_lease_set_value  (omapi_object_t *h,
206				    omapi_object_t *id,
207				    omapi_data_string_t *name,
208				    omapi_typed_data_t *value)
209{
210	struct lease *lease;
211	isc_result_t status;
212
213	if (h -> type != dhcp_type_lease)
214		return DHCP_R_INVALIDARG;
215	lease = (struct lease *)h;
216
217	/* We're skipping a lot of things it might be interesting to
218	   set - for now, we just make it possible to whack the state. */
219	if (!omapi_ds_strcmp (name, "state")) {
220	    unsigned long bar;
221	    const char *ols, *nls;
222	    status = omapi_get_int_value (&bar, value);
223	    if (status != ISC_R_SUCCESS)
224		return status;
225
226	    if (bar < 1 || bar > FTS_LAST)
227		return DHCP_R_INVALIDARG;
228	    nls = binding_state_names [bar - 1];
229	    if (lease -> binding_state >= 1 &&
230		lease -> binding_state <= FTS_LAST)
231		ols = binding_state_names [lease -> binding_state - 1];
232	    else
233		ols = "unknown state";
234
235	    if (lease -> binding_state != bar) {
236		lease -> next_binding_state = bar;
237		if (supersede_lease (lease, NULL, 1, 1, 1, 0)) {
238			log_info ("lease %s state changed from %s to %s",
239				  piaddr(lease->ip_addr), ols, nls);
240			return ISC_R_SUCCESS;
241		}
242		log_info ("lease %s state change from %s to %s failed.",
243			  piaddr (lease -> ip_addr), ols, nls);
244		return ISC_R_IOERROR;
245	    }
246	    return DHCP_R_UNCHANGED;
247	} else if (!omapi_ds_strcmp (name, "ip-address")) {
248	    return ISC_R_NOPERM;
249	} else if (!omapi_ds_strcmp (name, "dhcp-client-identifier")) {
250	    return DHCP_R_UNCHANGED;	/* XXX take change. */
251	} else if (!omapi_ds_strcmp (name, "hostname")) {
252	    return DHCP_R_UNCHANGED;	/* XXX take change. */
253	} else if (!omapi_ds_strcmp (name, "client-hostname")) {
254	    return DHCP_R_UNCHANGED;	/* XXX take change. */
255	} else if (!omapi_ds_strcmp (name, "host")) {
256	    return DHCP_R_UNCHANGED;	/* XXX take change. */
257	} else if (!omapi_ds_strcmp (name, "subnet")) {
258	    return DHCP_R_INVALIDARG;
259	} else if (!omapi_ds_strcmp (name, "pool")) {
260	    return ISC_R_NOPERM;
261	} else if (!omapi_ds_strcmp (name, "starts")) {
262	    return ISC_R_NOPERM;
263	} else if (!omapi_ds_strcmp (name, "ends")) {
264	    unsigned long lease_end, old_lease_end;
265	    status = omapi_get_int_value (&lease_end, value);
266	    if (status != ISC_R_SUCCESS)
267		return status;
268	    old_lease_end = lease->ends;
269	    lease->ends = lease_end;
270	    if (supersede_lease (lease, NULL, 1, 1, 1, 0)) {
271		log_info ("lease %s end changed from %lu to %lu",
272			  piaddr(lease->ip_addr), old_lease_end, lease_end);
273		return ISC_R_SUCCESS;
274	    }
275	    log_info ("lease %s end change from %lu to %lu failed",
276		      piaddr(lease->ip_addr), old_lease_end, lease_end);
277	    return ISC_R_IOERROR;
278	} else if (!omapi_ds_strcmp(name, "flags")) {
279	    return (update_lease_flags(lease, value));
280	} else if (!omapi_ds_strcmp (name, "billing-class")) {
281	    return DHCP_R_UNCHANGED;	/* XXX carefully allow change. */
282	} else if (!omapi_ds_strcmp (name, "hardware-address")) {
283	    return DHCP_R_UNCHANGED;	/* XXX take change. */
284	} else if (!omapi_ds_strcmp (name, "hardware-type")) {
285	    return DHCP_R_UNCHANGED;	/* XXX take change. */
286	} else if (lease -> scope) {
287	    status = binding_scope_set_value (lease -> scope, 0, name, value);
288	    if (status == ISC_R_SUCCESS) {
289		    if (write_lease (lease) && commit_leases ())
290			    return ISC_R_SUCCESS;
291		    return ISC_R_IOERROR;
292	    }
293	}
294
295	/* Try to find some inner object that can take the value. */
296	if (h -> inner && h -> inner -> type -> set_value) {
297		status = ((*(h -> inner -> type -> set_value))
298			  (h -> inner, id, name, value));
299		if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED)
300			return status;
301	}
302
303	if (!lease -> scope) {
304		if (!binding_scope_allocate (&lease -> scope, MDL))
305			return ISC_R_NOMEMORY;
306	}
307	status = binding_scope_set_value (lease -> scope, 1, name, value);
308	if (status != ISC_R_SUCCESS)
309		return status;
310
311	if (write_lease (lease) && commit_leases ())
312		return ISC_R_SUCCESS;
313	return ISC_R_IOERROR;
314}
315
316/*
317 * \brief Updates the lease's flags to a given value
318 *
319 * In order to update the lease's flags, we make a copy of the
320 * lease, and update the copy's flags with the new value.
321 * We then use the updated copy as the second parameter to a
322 * call to supersede_lease().  This ensures that the lease
323 * moves between queues correctly.   This is critical when
324 * the RESERVED_LEASE flag is being changed.
325 *
326 * Note that only the EPHEMERAL flags are permitted to be changed.
327 *
328 * \param lease - pointer to the lease to update
329 * \param value - omapi data value containing the new flags value
330 *
331 * \return ISC_R_SUCCESS if the lease was successfully updated,
332 *  DHCP_R_UNCHANGED if new value would result in no change to the
333 *  lease's flags, or an appropriate status on other errors
334 */
335static isc_result_t update_lease_flags(struct lease* lease,
336				       omapi_typed_data_t *value)
337{
338	u_int8_t oldflags;
339	u_int8_t newflags;
340	struct lease* lupdate = NULL;
341	isc_result_t status;
342
343	/* Grab the requested flags value. We (the server) send flags
344	 * out as 1-byte, so we expect clients to do the same.  However
345	 * omshell, will send a network-ordered 4 byte integer if the
346	 * input is "set flags = <n>", so we'll accomdate that too. */
347	if (value->u.buffer.len == 1) {
348		newflags = value->u.buffer.value[0];
349	} else {
350		unsigned long tmp;
351
352		status = omapi_get_int_value (&tmp, value);
353		if (status != ISC_R_SUCCESS) {
354			return (status);
355		}
356
357		newflags = (u_int8_t)tmp;
358	}
359
360	/* Save off the current flags value. */
361	oldflags = lease->flags;
362
363	/* The new value must preserve all PERSISTANT_FLAGS */
364	newflags = ((lease->flags & ~EPHEMERAL_FLAGS) |
365		    (newflags & EPHEMERAL_FLAGS));
366
367	/* If there's no net change, we're done */
368	if (oldflags == newflags) {
369		return (DHCP_R_UNCHANGED);
370	}
371
372	/* Make a copy of the lease. */
373	if (!lease_copy(&lupdate, lease, MDL)) {
374		return (ISC_R_FAILURE);
375	}
376
377	/* Set the copy's flags to the new value */
378	lupdate->flags = newflags;
379
380	/* Attempt to update the lease */
381	if (!supersede_lease(lease, lupdate, 1, 1, 1, 0)) {
382		log_error("Failed to update flags for lease %s.",
383			  piaddr(lease->ip_addr));
384		status = ISC_R_FAILURE;
385	} else {
386		log_debug ("lease flags changed from  %x to %x for lease %s.",
387			   oldflags, newflags, piaddr(lease->ip_addr));
388		status = ISC_R_SUCCESS;
389	}
390
391	lease_dereference(&lupdate, MDL);
392	return (status);
393}
394
395
396isc_result_t dhcp_lease_get_value (omapi_object_t *h, omapi_object_t *id,
397				   omapi_data_string_t *name,
398				   omapi_value_t **value)
399{
400	struct lease *lease;
401	isc_result_t status;
402
403	if (h -> type != dhcp_type_lease)
404		return DHCP_R_INVALIDARG;
405	lease = (struct lease *)h;
406
407	if (!omapi_ds_strcmp (name, "state"))
408		return omapi_make_int_value (value, name,
409					     (int)lease -> binding_state, MDL);
410	else if (!omapi_ds_strcmp (name, "ip-address"))
411		return omapi_make_const_value (value, name,
412					       lease -> ip_addr.iabuf,
413					       lease -> ip_addr.len, MDL);
414	else if (!omapi_ds_strcmp (name, "dhcp-client-identifier")) {
415		return omapi_make_const_value (value, name,
416					       lease -> uid,
417					       lease -> uid_len, MDL);
418	} else if (!omapi_ds_strcmp (name, "client-hostname")) {
419		if (lease -> client_hostname)
420			return omapi_make_string_value
421				(value, name, lease -> client_hostname, MDL);
422		return ISC_R_NOTFOUND;
423	} else if (!omapi_ds_strcmp (name, "host")) {
424		if (lease -> host)
425			return omapi_make_handle_value
426				(value, name,
427				 ((omapi_object_t *)lease -> host), MDL);
428	} else if (!omapi_ds_strcmp (name, "subnet"))
429		return omapi_make_handle_value (value, name,
430						((omapi_object_t *)
431						 lease -> subnet), MDL);
432	else if (!omapi_ds_strcmp (name, "pool"))
433		return omapi_make_handle_value (value, name,
434						((omapi_object_t *)
435						 lease -> pool), MDL);
436	else if (!omapi_ds_strcmp (name, "billing-class")) {
437		if (lease -> billing_class)
438			return omapi_make_handle_value
439				(value, name,
440				 ((omapi_object_t *)lease -> billing_class),
441				 MDL);
442		return ISC_R_NOTFOUND;
443	} else if (!omapi_ds_strcmp (name, "hardware-address")) {
444		if (lease -> hardware_addr.hlen)
445			return omapi_make_const_value
446				(value, name, &lease -> hardware_addr.hbuf [1],
447				 (unsigned)(lease -> hardware_addr.hlen - 1),
448				 MDL);
449		return ISC_R_NOTFOUND;
450	} else if (!omapi_ds_strcmp (name, "hardware-type")) {
451		if (lease -> hardware_addr.hlen)
452			return omapi_make_int_value
453				(value, name, lease -> hardware_addr.hbuf [0],
454				 MDL);
455		return ISC_R_NOTFOUND;
456	} else if (lease -> scope) {
457		status = binding_scope_get_value (value, lease -> scope, name);
458		if (status != ISC_R_NOTFOUND)
459			return status;
460	}
461
462	/* Try to find some inner object that can take the value. */
463	if (h -> inner && h -> inner -> type -> get_value) {
464		status = ((*(h -> inner -> type -> get_value))
465			  (h -> inner, id, name, value));
466		if (status == ISC_R_SUCCESS)
467			return status;
468	}
469	return DHCP_R_UNKNOWNATTRIBUTE;
470}
471
472isc_result_t dhcp_lease_destroy (omapi_object_t *h, const char *file, int line)
473{
474	struct lease *lease;
475
476	if (h->type != dhcp_type_lease)
477		return DHCP_R_INVALIDARG;
478	lease = (struct lease *)h;
479
480	if (lease-> uid)
481		uid_hash_delete (lease);
482	hw_hash_delete (lease);
483
484	if (lease->on_star.on_release)
485		executable_statement_dereference (&lease->on_star.on_release,
486						  file, line);
487	if (lease->on_star.on_expiry)
488		executable_statement_dereference (&lease->on_star.on_expiry,
489						  file, line);
490	if (lease->on_star.on_commit)
491		executable_statement_dereference (&lease->on_star.on_commit,
492						  file, line);
493	if (lease->scope)
494		binding_scope_dereference (&lease->scope, file, line);
495
496	if (lease->agent_options)
497		option_chain_head_dereference (&lease->agent_options,
498					       file, line);
499	if (lease->uid && lease->uid != lease->uid_buf) {
500		dfree (lease->uid, MDL);
501		lease->uid = &lease->uid_buf [0];
502		lease->uid_len = 0;
503	}
504
505	if (lease->client_hostname) {
506		dfree (lease->client_hostname, MDL);
507		lease->client_hostname = (char *)0;
508	}
509
510	if (lease->host)
511		host_dereference (&lease->host, file, line);
512	if (lease->subnet)
513		subnet_dereference (&lease->subnet, file, line);
514	if (lease->pool)
515		pool_dereference (&lease->pool, file, line);
516
517	if (lease->state) {
518		free_lease_state (lease->state, file, line);
519		lease->state = (struct lease_state *)0;
520
521		cancel_timeout (lease_ping_timeout, lease);
522		--outstanding_pings; /* XXX */
523	}
524
525	if (lease->billing_class)
526		class_dereference
527			(&lease->billing_class, file, line);
528
529	/* We no longer check for a next pointer as that should
530	 * be cleared when we destroy the pool and as before we
531	 * should only ever be doing that on exit.
532	if (lease->next)
533		lease_dereference (&lease->next, file, line);
534	 */
535
536	if (lease->n_hw)
537		lease_dereference (&lease->n_hw, file, line);
538	if (lease->n_uid)
539		lease_dereference (&lease->n_uid, file, line);
540	if (lease->next_pending)
541		lease_dereference (&lease->next_pending, file, line);
542
543	return ISC_R_SUCCESS;
544}
545
546isc_result_t dhcp_lease_signal_handler (omapi_object_t *h,
547					const char *name, va_list ap)
548{
549	/* h should point to (struct lease *) */
550	isc_result_t status;
551
552	if (h -> type != dhcp_type_lease)
553		return DHCP_R_INVALIDARG;
554
555	if (!strcmp (name, "updated"))
556		return ISC_R_SUCCESS;
557
558	/* Try to find some inner object that can take the value. */
559	if (h -> inner && h -> inner -> type -> signal_handler) {
560		status = ((*(h -> inner -> type -> signal_handler))
561			  (h -> inner, name, ap));
562		if (status == ISC_R_SUCCESS)
563			return status;
564	}
565	return ISC_R_NOTFOUND;
566}
567
568isc_result_t dhcp_lease_stuff_values (omapi_object_t *c,
569				      omapi_object_t *id,
570				      omapi_object_t *h)
571{
572	u_int32_t bouncer;
573	struct lease *lease;
574	isc_result_t status;
575	u_int8_t flagbuf;
576
577	if (h -> type != dhcp_type_lease)
578		return DHCP_R_INVALIDARG;
579	lease = (struct lease *)h;
580
581	/* Write out all the values. */
582
583	status = omapi_connection_put_named_uint32(c, "state",
584						   lease->binding_state);
585	if (status != ISC_R_SUCCESS)
586		return (status);
587
588	status = omapi_connection_put_name (c, "ip-address");
589	if (status != ISC_R_SUCCESS)
590		return status;
591	status = omapi_connection_put_uint32 (c, lease -> ip_addr.len);
592	if (status != ISC_R_SUCCESS)
593		return status;
594	status = omapi_connection_copyin (c, lease -> ip_addr.iabuf,
595					  lease -> ip_addr.len);
596	if (status != ISC_R_SUCCESS)
597		return status;
598
599	if (lease -> uid_len) {
600		status = omapi_connection_put_name (c,
601						    "dhcp-client-identifier");
602		if (status != ISC_R_SUCCESS)
603			return status;
604		status = omapi_connection_put_uint32 (c, lease -> uid_len);
605		if (status != ISC_R_SUCCESS)
606			return status;
607		if (lease -> uid_len) {
608			status = omapi_connection_copyin (c, lease -> uid,
609							  lease -> uid_len);
610			if (status != ISC_R_SUCCESS)
611				return status;
612		}
613	}
614
615	if (lease -> client_hostname) {
616		status = omapi_connection_put_name (c, "client-hostname");
617		if (status != ISC_R_SUCCESS)
618			return status;
619		status =
620			omapi_connection_put_string (c,
621						     lease -> client_hostname);
622		if (status != ISC_R_SUCCESS)
623			return status;
624	}
625
626	if (lease -> host) {
627		status = omapi_connection_put_name (c, "host");
628		if (status != ISC_R_SUCCESS)
629			return status;
630		status = omapi_connection_put_handle (c,
631						      (omapi_object_t *)
632						      lease -> host);
633		if (status != ISC_R_SUCCESS)
634			return status;
635	}
636
637	status = omapi_connection_put_name (c, "subnet");
638	if (status != ISC_R_SUCCESS)
639		return status;
640	status = omapi_connection_put_handle
641		(c, (omapi_object_t *)lease -> subnet);
642	if (status != ISC_R_SUCCESS)
643		return status;
644
645	status = omapi_connection_put_name (c, "pool");
646	if (status != ISC_R_SUCCESS)
647		return status;
648	status = omapi_connection_put_handle (c,
649					      (omapi_object_t *)lease -> pool);
650	if (status != ISC_R_SUCCESS)
651		return status;
652
653	if (lease -> billing_class) {
654		status = omapi_connection_put_name (c, "billing-class");
655		if (status != ISC_R_SUCCESS)
656			return status;
657		status = omapi_connection_put_handle
658			(c, (omapi_object_t *)lease -> billing_class);
659		if (status != ISC_R_SUCCESS)
660			return status;
661	}
662
663	if (lease -> hardware_addr.hlen) {
664		status = omapi_connection_put_name (c, "hardware-address");
665		if (status != ISC_R_SUCCESS)
666			return status;
667		status = (omapi_connection_put_uint32
668			  (c,
669			   (unsigned long)(lease -> hardware_addr.hlen - 1)));
670		if (status != ISC_R_SUCCESS)
671			return status;
672		status = (omapi_connection_copyin
673			  (c, &lease -> hardware_addr.hbuf [1],
674			   (unsigned long)(lease -> hardware_addr.hlen - 1)));
675
676		if (status != ISC_R_SUCCESS)
677			return status;
678
679		status = omapi_connection_put_named_uint32(c, "hardware-type",
680						lease->hardware_addr.hbuf[0]);
681		if (status != ISC_R_SUCCESS)
682			return (status);
683	}
684
685	/* TIME values may be 64-bit, depending on system architecture.
686	 * OMAPI must be system independent, both in terms of transmitting
687	 * bytes on the wire in network byte order, and in terms of being
688	 * readable and usable by both systems.
689	 *
690	 * XXX: In a future feature release, a put_int64() should be made
691	 * to exist, and perhaps a put_time() wrapper that selects which
692	 * to use based upon sizeof(TIME).  In the meantime, use existing,
693	 * 32-bit, code.
694	 */
695	bouncer = (u_int32_t)lease->ends;
696	status = omapi_connection_put_named_uint32(c, "ends", bouncer);
697	if (status != ISC_R_SUCCESS)
698		return (status);
699
700	bouncer = (u_int32_t)lease->starts;
701	status = omapi_connection_put_named_uint32(c, "starts", bouncer);
702	if (status != ISC_R_SUCCESS)
703		return (status);
704
705	bouncer = (u_int32_t)lease->tstp;
706	status = omapi_connection_put_named_uint32(c, "tstp", bouncer);
707	if (status != ISC_R_SUCCESS)
708		return (status);
709
710	bouncer = (u_int32_t)lease->tsfp;
711	status = omapi_connection_put_named_uint32(c, "tsfp", bouncer);
712	if (status != ISC_R_SUCCESS)
713		return status;
714
715	bouncer = (u_int32_t)lease->atsfp;
716	status = omapi_connection_put_named_uint32(c, "atsfp", bouncer);
717	if (status != ISC_R_SUCCESS)
718		return status;
719
720	bouncer = (u_int32_t)lease->cltt;
721	status = omapi_connection_put_named_uint32(c, "cltt", bouncer);
722	if (status != ISC_R_SUCCESS)
723		return status;
724
725	status = omapi_connection_put_name (c, "flags");
726	if (status != ISC_R_SUCCESS)
727		return status;
728	status = omapi_connection_put_uint32(c, sizeof(flagbuf));
729	if (status != ISC_R_SUCCESS)
730		return status;
731	flagbuf = lease->flags & EPHEMERAL_FLAGS;
732	status = omapi_connection_copyin(c, &flagbuf, sizeof(flagbuf));
733	if (status != ISC_R_SUCCESS)
734		return status;
735
736	if (lease -> scope) {
737		status = binding_scope_stuff_values (c, lease -> scope);
738		if (status != ISC_R_SUCCESS)
739			return status;
740	}
741
742	/* Write out the inner object, if any. */
743	if (h -> inner && h -> inner -> type -> stuff_values) {
744		status = ((*(h -> inner -> type -> stuff_values))
745			  (c, id, h -> inner));
746		if (status == ISC_R_SUCCESS)
747			return status;
748	}
749
750	return ISC_R_SUCCESS;
751}
752
753isc_result_t dhcp_lease_lookup (omapi_object_t **lp,
754				omapi_object_t *id, omapi_object_t *ref)
755{
756	omapi_value_t *tv = (omapi_value_t *)0;
757	isc_result_t status;
758	struct lease *lease;
759
760	if (!ref)
761		return DHCP_R_NOKEYS;
762
763	/* First see if we were sent a handle. */
764	status = omapi_get_value_str (ref, id, "handle", &tv);
765	if (status == ISC_R_SUCCESS) {
766		status = omapi_handle_td_lookup (lp, tv -> value);
767
768		omapi_value_dereference (&tv, MDL);
769		if (status != ISC_R_SUCCESS)
770			return status;
771
772		/* Don't return the object if the type is wrong. */
773		if ((*lp) -> type != dhcp_type_lease) {
774			omapi_object_dereference (lp, MDL);
775			return DHCP_R_INVALIDARG;
776		}
777	}
778
779	/* Now look for an IP address. */
780	status = omapi_get_value_str (ref, id, "ip-address", &tv);
781	if (status == ISC_R_SUCCESS) {
782		lease = (struct lease *)0;
783		lease_ip_hash_lookup(&lease, lease_ip_addr_hash,
784				     tv->value->u.buffer.value,
785				     tv->value->u.buffer.len, MDL);
786
787		omapi_value_dereference (&tv, MDL);
788
789		/* If we already have a lease, and it's not the same one,
790		   then the query was invalid. */
791		if (*lp && *lp != (omapi_object_t *)lease) {
792			omapi_object_dereference (lp, MDL);
793			lease_dereference (&lease, MDL);
794			return DHCP_R_KEYCONFLICT;
795		} else if (!lease) {
796			if (*lp)
797				omapi_object_dereference (lp, MDL);
798			return ISC_R_NOTFOUND;
799		} else if (!*lp) {
800			/* XXX fix so that hash lookup itself creates
801			   XXX the reference. */
802			omapi_object_reference (lp,
803						(omapi_object_t *)lease, MDL);
804			lease_dereference (&lease, MDL);
805		}
806	}
807
808	/* Now look for a client identifier. */
809	status = omapi_get_value_str (ref, id, "dhcp-client-identifier", &tv);
810	if (status == ISC_R_SUCCESS) {
811		lease = (struct lease *)0;
812		lease_id_hash_lookup(&lease, lease_uid_hash,
813				     tv->value->u.buffer.value,
814				     tv->value->u.buffer.len, MDL);
815		omapi_value_dereference (&tv, MDL);
816
817		if (*lp && *lp != (omapi_object_t *)lease) {
818			omapi_object_dereference (lp, MDL);
819			lease_dereference (&lease, MDL);
820			return DHCP_R_KEYCONFLICT;
821		} else if (!lease) {
822			if (*lp)
823			    omapi_object_dereference (lp, MDL);
824			return ISC_R_NOTFOUND;
825		} else if (lease -> n_uid) {
826			if (*lp)
827			    omapi_object_dereference (lp, MDL);
828			return DHCP_R_MULTIPLE;
829		} else if (!*lp) {
830			/* XXX fix so that hash lookup itself creates
831			   XXX the reference. */
832			omapi_object_reference (lp,
833						(omapi_object_t *)lease, MDL);
834			lease_dereference (&lease, MDL);
835		}
836	}
837
838	/* Now look for a hardware address. */
839	status = omapi_get_value_str (ref, id, "hardware-address", &tv);
840	if (status == ISC_R_SUCCESS) {
841		unsigned char *haddr;
842		unsigned int len;
843
844		len = tv -> value -> u.buffer.len + 1;
845		haddr = dmalloc (len, MDL);
846		if (!haddr) {
847			omapi_value_dereference (&tv, MDL);
848			return ISC_R_NOMEMORY;
849		}
850
851		memcpy (haddr + 1, tv -> value -> u.buffer.value, len - 1);
852		omapi_value_dereference (&tv, MDL);
853
854		status = omapi_get_value_str (ref, id, "hardware-type", &tv);
855		if (status == ISC_R_SUCCESS) {
856			if (tv -> value -> type == omapi_datatype_data) {
857				if ((tv -> value -> u.buffer.len != 4) ||
858				    (tv -> value -> u.buffer.value[0] != 0) ||
859				    (tv -> value -> u.buffer.value[1] != 0) ||
860				    (tv -> value -> u.buffer.value[2] != 0)) {
861					omapi_value_dereference (&tv, MDL);
862					dfree (haddr, MDL);
863					return DHCP_R_INVALIDARG;
864				}
865
866				haddr[0] = tv -> value -> u.buffer.value[3];
867			} else if (tv -> value -> type == omapi_datatype_int) {
868				haddr[0] = (unsigned char)
869					tv -> value -> u.integer;
870			} else {
871				omapi_value_dereference (&tv, MDL);
872				dfree (haddr, MDL);
873				return DHCP_R_INVALIDARG;
874			}
875
876			omapi_value_dereference (&tv, MDL);
877		} else {
878			/* If no hardware-type is specified, default to
879			   ethernet.  This may or may not be a good idea,
880			   but Telus is currently relying on this behavior.
881			   - DPN */
882			haddr[0] = HTYPE_ETHER;
883		}
884
885		lease = (struct lease *)0;
886		lease_id_hash_lookup(&lease, lease_hw_addr_hash, haddr, len,
887				     MDL);
888		dfree (haddr, MDL);
889
890		if (*lp && *lp != (omapi_object_t *)lease) {
891			omapi_object_dereference (lp, MDL);
892			lease_dereference (&lease, MDL);
893			return DHCP_R_KEYCONFLICT;
894		} else if (!lease) {
895			if (*lp)
896			    omapi_object_dereference (lp, MDL);
897			return ISC_R_NOTFOUND;
898		} else if (lease -> n_hw) {
899			if (*lp)
900			    omapi_object_dereference (lp, MDL);
901			lease_dereference (&lease, MDL);
902			return DHCP_R_MULTIPLE;
903		} else if (!*lp) {
904			/* XXX fix so that hash lookup itself creates
905			   XXX the reference. */
906			omapi_object_reference (lp,
907						(omapi_object_t *)lease, MDL);
908			lease_dereference (&lease, MDL);
909		}
910	}
911
912	/* If we get to here without finding a lease, no valid key was
913	   specified. */
914	if (!*lp)
915		return DHCP_R_NOKEYS;
916	return ISC_R_SUCCESS;
917}
918
919isc_result_t dhcp_lease_create (omapi_object_t **lp,
920				omapi_object_t *id)
921{
922	return ISC_R_NOTIMPLEMENTED;
923}
924
925isc_result_t dhcp_lease_remove (omapi_object_t *lp,
926				omapi_object_t *id)
927{
928	return ISC_R_NOTIMPLEMENTED;
929}
930
931isc_result_t dhcp_host_set_value  (omapi_object_t *h,
932				   omapi_object_t *id,
933				   omapi_data_string_t *name,
934				   omapi_typed_data_t *value)
935{
936	struct host_decl *host;
937	isc_result_t status;
938
939	if (h -> type != dhcp_type_host)
940		return DHCP_R_INVALIDARG;
941	host = (struct host_decl *)h;
942
943	/* XXX For now, we can only set these values on new host objects.
944	   XXX Soon, we need to be able to update host objects. */
945	if (!omapi_ds_strcmp (name, "name")) {
946		if (host -> name)
947			return ISC_R_EXISTS;
948		if (value && (value -> type == omapi_datatype_data ||
949			      value -> type == omapi_datatype_string)) {
950			host -> name = dmalloc (value -> u.buffer.len + 1,
951						MDL);
952			if (!host -> name)
953				return ISC_R_NOMEMORY;
954			memcpy (host -> name,
955				value -> u.buffer.value,
956				value -> u.buffer.len);
957			host -> name [value -> u.buffer.len] = 0;
958		} else
959			return DHCP_R_INVALIDARG;
960		return ISC_R_SUCCESS;
961	}
962
963	if (!omapi_ds_strcmp (name, "group")) {
964		if (value && (value -> type == omapi_datatype_data ||
965			      value -> type == omapi_datatype_string)) {
966			struct group_object *group;
967			group = (struct group_object *)0;
968			group_hash_lookup (&group, group_name_hash,
969					   (char *)value -> u.buffer.value,
970					   value -> u.buffer.len, MDL);
971			if (!group || (group -> flags & GROUP_OBJECT_DELETED))
972				return ISC_R_NOTFOUND;
973			if (host -> group)
974				group_dereference (&host -> group, MDL);
975			group_reference (&host -> group, group -> group, MDL);
976			if (host -> named_group)
977				group_object_dereference (&host -> named_group,
978							  MDL);
979			group_object_reference (&host -> named_group,
980						group, MDL);
981			group_object_dereference (&group, MDL);
982		} else
983			return DHCP_R_INVALIDARG;
984		return ISC_R_SUCCESS;
985	}
986
987	if (!omapi_ds_strcmp (name, "hardware-address")) {
988		if (host -> interface.hlen)
989			return ISC_R_EXISTS;
990		if (value && (value -> type == omapi_datatype_data ||
991			      value -> type == omapi_datatype_string)) {
992			if (value -> u.buffer.len >
993			    (sizeof host -> interface.hbuf) - 1)
994				return DHCP_R_INVALIDARG;
995			memcpy (&host -> interface.hbuf [1],
996				value -> u.buffer.value,
997				value -> u.buffer.len);
998			host -> interface.hlen = value -> u.buffer.len + 1;
999		} else
1000			return DHCP_R_INVALIDARG;
1001		return ISC_R_SUCCESS;
1002	}
1003
1004	if (!omapi_ds_strcmp (name, "hardware-type")) {
1005		int type;
1006		if ((value != NULL) &&
1007		    ((value->type == omapi_datatype_data) &&
1008		     (value->u.buffer.len == sizeof(type)))) {
1009			if (value->u.buffer.len > sizeof(type))
1010				return (DHCP_R_INVALIDARG);
1011			memcpy(&type, value->u.buffer.value,
1012			       value->u.buffer.len);
1013			type = ntohl(type);
1014		} else if ((value != NULL) &&
1015			   (value->type == omapi_datatype_int))
1016			type = value->u.integer;
1017		else
1018			return (DHCP_R_INVALIDARG);
1019		host->interface.hbuf[0] = type;
1020		return (ISC_R_SUCCESS);
1021	}
1022
1023	if (!omapi_ds_strcmp (name, "dhcp-client-identifier")) {
1024		if (host -> client_identifier.data)
1025			return ISC_R_EXISTS;
1026		if (value && (value -> type == omapi_datatype_data ||
1027			      value -> type == omapi_datatype_string)) {
1028		    if (!buffer_allocate (&host -> client_identifier.buffer,
1029					  value -> u.buffer.len, MDL))
1030			    return ISC_R_NOMEMORY;
1031		    host -> client_identifier.data =
1032			    &host -> client_identifier.buffer -> data [0];
1033		    memcpy (host -> client_identifier.buffer -> data,
1034			    value -> u.buffer.value,
1035			    value -> u.buffer.len);
1036		    host -> client_identifier.len = value -> u.buffer.len;
1037		} else
1038		    return DHCP_R_INVALIDARG;
1039		return ISC_R_SUCCESS;
1040	}
1041
1042	if (!omapi_ds_strcmp (name, "ip-address")) {
1043		if (host -> fixed_addr)
1044			option_cache_dereference (&host -> fixed_addr, MDL);
1045		if (!value)
1046			return ISC_R_SUCCESS;
1047		if (value && (value -> type == omapi_datatype_data ||
1048			      value -> type == omapi_datatype_string)) {
1049			struct data_string ds;
1050			memset (&ds, 0, sizeof ds);
1051			ds.len = value -> u.buffer.len;
1052			if (!buffer_allocate (&ds.buffer, ds.len, MDL))
1053				return ISC_R_NOMEMORY;
1054			ds.data = (&ds.buffer -> data [0]);
1055			memcpy (ds.buffer -> data,
1056				value -> u.buffer.value, ds.len);
1057			if (!option_cache (&host -> fixed_addr,
1058					   &ds, (struct expression *)0,
1059					   (struct option *)0, MDL)) {
1060				data_string_forget (&ds, MDL);
1061				return ISC_R_NOMEMORY;
1062			}
1063			data_string_forget (&ds, MDL);
1064		} else
1065			return DHCP_R_INVALIDARG;
1066		return ISC_R_SUCCESS;
1067	}
1068
1069	if (!omapi_ds_strcmp (name, "statements")) {
1070		if (!host -> group) {
1071			if (!clone_group (&host -> group, root_group, MDL))
1072				return ISC_R_NOMEMORY;
1073		} else {
1074			if (host -> group -> statements &&
1075			    (!host -> named_group ||
1076			     host -> group != host -> named_group -> group) &&
1077			    host -> group != root_group)
1078				return ISC_R_EXISTS;
1079			if (!clone_group (&host -> group, host -> group, MDL))
1080				return ISC_R_NOMEMORY;
1081		}
1082		if (!host -> group)
1083			return ISC_R_NOMEMORY;
1084		if (value && (value -> type == omapi_datatype_data ||
1085			      value -> type == omapi_datatype_string)) {
1086			struct parse *parse;
1087			int lose = 0;
1088			parse = (struct parse *)0;
1089			status = new_parse(&parse, -1,
1090					    (char *) value->u.buffer.value,
1091					    value->u.buffer.len,
1092					    "network client", 0);
1093			if (status != ISC_R_SUCCESS || parse == NULL)
1094				return status;
1095
1096			if (!(parse_executable_statements
1097			      (&host -> group -> statements, parse, &lose,
1098			       context_any))) {
1099				end_parse (&parse);
1100				return DHCP_R_BADPARSE;
1101			}
1102			end_parse (&parse);
1103		} else
1104			return DHCP_R_INVALIDARG;
1105		return ISC_R_SUCCESS;
1106	}
1107
1108	/* The "known" flag isn't supported in the database yet, but it's
1109	   legitimate. */
1110	if (!omapi_ds_strcmp (name, "known")) {
1111		return ISC_R_SUCCESS;
1112	}
1113
1114	/* Try to find some inner object that can take the value. */
1115	if (h -> inner && h -> inner -> type -> set_value) {
1116		status = ((*(h -> inner -> type -> set_value))
1117			  (h -> inner, id, name, value));
1118		if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED)
1119			return status;
1120	}
1121
1122	return DHCP_R_UNKNOWNATTRIBUTE;
1123}
1124
1125
1126isc_result_t dhcp_host_get_value (omapi_object_t *h, omapi_object_t *id,
1127				   omapi_data_string_t *name,
1128				   omapi_value_t **value)
1129{
1130	struct host_decl *host;
1131	isc_result_t status;
1132	struct data_string ip_addrs;
1133
1134	if (h -> type != dhcp_type_host)
1135		return DHCP_R_INVALIDARG;
1136	host = (struct host_decl *)h;
1137
1138	if (!omapi_ds_strcmp (name, "ip-addresses")) {
1139	    memset (&ip_addrs, 0, sizeof ip_addrs);
1140	    if (host -> fixed_addr &&
1141		evaluate_option_cache (&ip_addrs, (struct packet *)0,
1142				       (struct lease *)0,
1143				       (struct client_state *)0,
1144				       (struct option_state *)0,
1145				       (struct option_state *)0,
1146				       &global_scope,
1147				       host -> fixed_addr, MDL)) {
1148		    status = omapi_make_const_value (value, name,
1149						     ip_addrs.data,
1150						     ip_addrs.len, MDL);
1151		    data_string_forget (&ip_addrs, MDL);
1152		    return status;
1153	    }
1154	    return ISC_R_NOTFOUND;
1155	}
1156
1157	if (!omapi_ds_strcmp (name, "dhcp-client-identifier")) {
1158		if (!host -> client_identifier.len)
1159			return ISC_R_NOTFOUND;
1160		return omapi_make_const_value (value, name,
1161					       host -> client_identifier.data,
1162					       host -> client_identifier.len,
1163					       MDL);
1164	}
1165
1166	if (!omapi_ds_strcmp (name, "name"))
1167		return omapi_make_string_value (value, name, host -> name,
1168						MDL);
1169
1170	if (!omapi_ds_strcmp (name, "hardware-address")) {
1171		if (!host -> interface.hlen)
1172			return ISC_R_NOTFOUND;
1173		return (omapi_make_const_value
1174			(value, name, &host -> interface.hbuf [1],
1175			 (unsigned long)(host -> interface.hlen - 1), MDL));
1176	}
1177
1178	if (!omapi_ds_strcmp (name, "hardware-type")) {
1179		if (!host -> interface.hlen)
1180			return ISC_R_NOTFOUND;
1181		return omapi_make_int_value (value, name,
1182					     host -> interface.hbuf [0], MDL);
1183	}
1184
1185	/* Try to find some inner object that can take the value. */
1186	if (h -> inner && h -> inner -> type -> get_value) {
1187		status = ((*(h -> inner -> type -> get_value))
1188			  (h -> inner, id, name, value));
1189		if (status == ISC_R_SUCCESS)
1190			return status;
1191	}
1192	return DHCP_R_UNKNOWNATTRIBUTE;
1193}
1194
1195isc_result_t dhcp_host_destroy (omapi_object_t *h, const char *file, int line)
1196{
1197
1198	if (h -> type != dhcp_type_host)
1199		return DHCP_R_INVALIDARG;
1200
1201	struct host_decl *host = (struct host_decl *)h;
1202	if (host -> n_ipaddr)
1203		host_dereference (&host -> n_ipaddr, file, line);
1204	if (host -> n_dynamic)
1205		host_dereference (&host -> n_dynamic, file, line);
1206	if (host -> name) {
1207		dfree (host -> name, file, line);
1208		host -> name = (char *)0;
1209	}
1210	data_string_forget (&host -> client_identifier, file, line);
1211	if (host -> fixed_addr)
1212		option_cache_dereference (&host -> fixed_addr, file, line);
1213	if (host -> group)
1214		group_dereference (&host -> group, file, line);
1215	if (host -> named_group)
1216		omapi_object_dereference ((omapi_object_t **)
1217					  &host -> named_group, file, line);
1218	data_string_forget (&host -> auth_key_id, file, line);
1219
1220	return ISC_R_SUCCESS;
1221}
1222
1223isc_result_t dhcp_host_signal_handler (omapi_object_t *h,
1224				       const char *name, va_list ap)
1225{
1226	struct host_decl *host;
1227	isc_result_t status;
1228	int updatep = 0;
1229
1230	if (h -> type != dhcp_type_host)
1231		return DHCP_R_INVALIDARG;
1232	host = (struct host_decl *)h;
1233
1234	if (!strcmp (name, "updated")) {
1235		/* There must be a client identifier of some sort. */
1236		if (host -> interface.hlen == 0 &&
1237		    !host -> client_identifier.len)
1238			return DHCP_R_INVALIDARG;
1239
1240		if (!host -> name) {
1241			char hnbuf [64];
1242			sprintf (hnbuf, "nh%08lx%08lx",
1243				 (unsigned long)cur_time, (unsigned long)host);
1244			host -> name = dmalloc (strlen (hnbuf) + 1, MDL);
1245			if (!host -> name)
1246				return ISC_R_NOMEMORY;
1247			strcpy (host -> name, hnbuf);
1248		}
1249
1250#ifdef DEBUG_OMAPI
1251		log_debug ("OMAPI added host %s", host -> name);
1252#endif
1253		status = enter_host (host, 1, 1);
1254		if (status != ISC_R_SUCCESS)
1255			return status;
1256		updatep = 1;
1257	}
1258
1259	/* Try to find some inner object that can take the value. */
1260	if (h -> inner && h -> inner -> type -> signal_handler) {
1261		status = ((*(h -> inner -> type -> signal_handler))
1262			  (h -> inner, name, ap));
1263		if (status == ISC_R_SUCCESS)
1264			return status;
1265	}
1266	if (updatep)
1267		return ISC_R_SUCCESS;
1268	return ISC_R_NOTFOUND;
1269}
1270
1271isc_result_t dhcp_host_stuff_values (omapi_object_t *c,
1272				     omapi_object_t *id,
1273				     omapi_object_t *h)
1274{
1275	struct host_decl *host;
1276	isc_result_t status;
1277	struct data_string ip_addrs;
1278
1279	if (h -> type != dhcp_type_host)
1280		return DHCP_R_INVALIDARG;
1281	host = (struct host_decl *)h;
1282
1283	/* Write out all the values. */
1284
1285	memset (&ip_addrs, 0, sizeof ip_addrs);
1286	if (host -> fixed_addr &&
1287	    evaluate_option_cache (&ip_addrs, (struct packet *)0,
1288				   (struct lease *)0,
1289				   (struct client_state *)0,
1290				   (struct option_state *)0,
1291				   (struct option_state *)0,
1292				   &global_scope,
1293				   host -> fixed_addr, MDL)) {
1294
1295		status = omapi_connection_put_name (c, "ip-address");
1296		if (status != ISC_R_SUCCESS) {
1297			data_string_forget (&ip_addrs, MDL);
1298			return status;
1299		}
1300
1301		status = omapi_connection_put_uint32 (c, ip_addrs.len);
1302		if (status != ISC_R_SUCCESS) {
1303			data_string_forget (&ip_addrs, MDL);
1304			return status;
1305		}
1306
1307		status = omapi_connection_copyin (c,
1308						  ip_addrs.data, ip_addrs.len);
1309		if (status != ISC_R_SUCCESS) {
1310			data_string_forget (&ip_addrs, MDL);
1311			return status;
1312		}
1313
1314		data_string_forget (&ip_addrs, MDL);
1315	}
1316
1317	if (host -> client_identifier.len) {
1318		status = omapi_connection_put_name (c,
1319						    "dhcp-client-identifier");
1320		if (status != ISC_R_SUCCESS)
1321			return status;
1322		status = (omapi_connection_put_uint32
1323			  (c, host -> client_identifier.len));
1324		if (status != ISC_R_SUCCESS)
1325			return status;
1326		status = (omapi_connection_copyin
1327			  (c,
1328			   host -> client_identifier.data,
1329			   host -> client_identifier.len));
1330		if (status != ISC_R_SUCCESS)
1331			return status;
1332	}
1333
1334	if (host -> name) {
1335		status = omapi_connection_put_name (c, "name");
1336		if (status != ISC_R_SUCCESS)
1337			return status;
1338		status = omapi_connection_put_string (c, host -> name);
1339		if (status != ISC_R_SUCCESS)
1340			return status;
1341	}
1342
1343	if (host -> interface.hlen) {
1344		status = omapi_connection_put_name (c, "hardware-address");
1345		if (status != ISC_R_SUCCESS)
1346			return status;
1347		status = (omapi_connection_put_uint32
1348			  (c, (unsigned long)(host -> interface.hlen - 1)));
1349		if (status != ISC_R_SUCCESS)
1350			return status;
1351		status = (omapi_connection_copyin
1352			  (c, &host -> interface.hbuf [1],
1353			   (unsigned long)(host -> interface.hlen - 1)));
1354		if (status != ISC_R_SUCCESS)
1355			return status;
1356
1357		status = omapi_connection_put_named_uint32(c, "hardware-type",
1358							   host->interface.hbuf[0]);
1359		if (status != ISC_R_SUCCESS)
1360			return status;
1361	}
1362
1363	/* Write out the inner object, if any. */
1364	if (h -> inner && h -> inner -> type -> stuff_values) {
1365		status = ((*(h -> inner -> type -> stuff_values))
1366			  (c, id, h -> inner));
1367		if (status == ISC_R_SUCCESS)
1368			return status;
1369	}
1370
1371	return ISC_R_SUCCESS;
1372}
1373
1374isc_result_t dhcp_host_lookup (omapi_object_t **lp,
1375			       omapi_object_t *id, omapi_object_t *ref)
1376{
1377	omapi_value_t *tv = (omapi_value_t *)0;
1378	isc_result_t status;
1379	struct host_decl *host;
1380
1381	if (!ref)
1382		return DHCP_R_NOKEYS;
1383
1384	/* First see if we were sent a handle. */
1385	status = omapi_get_value_str (ref, id, "handle", &tv);
1386	if (status == ISC_R_SUCCESS) {
1387		status = omapi_handle_td_lookup (lp, tv -> value);
1388
1389		omapi_value_dereference (&tv, MDL);
1390		if (status != ISC_R_SUCCESS)
1391			return status;
1392
1393		/* Don't return the object if the type is wrong. */
1394		if ((*lp) -> type != dhcp_type_host) {
1395			omapi_object_dereference (lp, MDL);
1396			return DHCP_R_INVALIDARG;
1397		}
1398		if (((struct host_decl *)(*lp)) -> flags & HOST_DECL_DELETED) {
1399			omapi_object_dereference (lp, MDL);
1400		}
1401	}
1402
1403	/* Now look for a client identifier. */
1404	status = omapi_get_value_str (ref, id, "dhcp-client-identifier", &tv);
1405	if (status == ISC_R_SUCCESS) {
1406		host = (struct host_decl *)0;
1407		host_hash_lookup (&host, host_uid_hash,
1408				  tv -> value -> u.buffer.value,
1409				  tv -> value -> u.buffer.len, MDL);
1410		omapi_value_dereference (&tv, MDL);
1411
1412		if (*lp && *lp != (omapi_object_t *)host) {
1413			omapi_object_dereference (lp, MDL);
1414			if (host)
1415				host_dereference (&host, MDL);
1416			return DHCP_R_KEYCONFLICT;
1417		} else if (!host || (host -> flags & HOST_DECL_DELETED)) {
1418			if (*lp)
1419			    omapi_object_dereference (lp, MDL);
1420			if (host)
1421				host_dereference (&host, MDL);
1422			return ISC_R_NOTFOUND;
1423		} else if (!*lp) {
1424			/* XXX fix so that hash lookup itself creates
1425			   XXX the reference. */
1426			omapi_object_reference (lp,
1427						(omapi_object_t *)host, MDL);
1428			host_dereference (&host, MDL);
1429		}
1430	}
1431
1432	/* Now look for a hardware address. */
1433	status = omapi_get_value_str (ref, id, "hardware-address", &tv);
1434	if (status == ISC_R_SUCCESS) {
1435		unsigned char *haddr;
1436		unsigned int len;
1437
1438		len = tv -> value -> u.buffer.len + 1;
1439		haddr = dmalloc (len, MDL);
1440		if (!haddr) {
1441			omapi_value_dereference (&tv, MDL);
1442			return ISC_R_NOMEMORY;
1443		}
1444
1445		memcpy (haddr + 1, tv -> value -> u.buffer.value, len - 1);
1446		omapi_value_dereference (&tv, MDL);
1447
1448		status = omapi_get_value_str (ref, id, "hardware-type", &tv);
1449		if (status == ISC_R_SUCCESS) {
1450			if (tv -> value -> type == omapi_datatype_data) {
1451				if ((tv -> value -> u.buffer.len != 4) ||
1452				    (tv -> value -> u.buffer.value[0] != 0) ||
1453				    (tv -> value -> u.buffer.value[1] != 0) ||
1454				    (tv -> value -> u.buffer.value[2] != 0)) {
1455					omapi_value_dereference (&tv, MDL);
1456					dfree (haddr, MDL);
1457					return DHCP_R_INVALIDARG;
1458				}
1459
1460				haddr[0] = tv -> value -> u.buffer.value[3];
1461			} else if (tv -> value -> type == omapi_datatype_int) {
1462				haddr[0] = (unsigned char)
1463					tv -> value -> u.integer;
1464			} else {
1465				omapi_value_dereference (&tv, MDL);
1466				dfree (haddr, MDL);
1467				return DHCP_R_INVALIDARG;
1468			}
1469
1470			omapi_value_dereference (&tv, MDL);
1471		} else {
1472			/* If no hardware-type is specified, default to
1473			   ethernet.  This may or may not be a good idea,
1474			   but Telus is currently relying on this behavior.
1475			   - DPN */
1476			haddr[0] = HTYPE_ETHER;
1477		}
1478
1479		host = (struct host_decl *)0;
1480		host_hash_lookup (&host, host_hw_addr_hash, haddr, len, MDL);
1481		dfree (haddr, MDL);
1482
1483		if (*lp && *lp != (omapi_object_t *)host) {
1484			omapi_object_dereference (lp, MDL);
1485			if (host)
1486				host_dereference (&host, MDL);
1487			return DHCP_R_KEYCONFLICT;
1488		} else if (!host || (host -> flags & HOST_DECL_DELETED)) {
1489			if (*lp)
1490			    omapi_object_dereference (lp, MDL);
1491			if (host)
1492				host_dereference (&host, MDL);
1493			return ISC_R_NOTFOUND;
1494		} else if (!*lp) {
1495			/* XXX fix so that hash lookup itself creates
1496			   XXX the reference. */
1497			omapi_object_reference (lp,
1498						(omapi_object_t *)host, MDL);
1499			host_dereference (&host, MDL);
1500		}
1501	}
1502
1503	/* Now look for an ip address. */
1504	status = omapi_get_value_str (ref, id, "ip-address", &tv);
1505	if (status == ISC_R_SUCCESS) {
1506		struct lease *l;
1507
1508		/* first find the lease for this ip address */
1509		l = (struct lease *)0;
1510		lease_ip_hash_lookup(&l, lease_ip_addr_hash,
1511				     tv->value->u.buffer.value,
1512				     tv->value->u.buffer.len, MDL);
1513		omapi_value_dereference (&tv, MDL);
1514
1515		if (!l && !*lp)
1516			return ISC_R_NOTFOUND;
1517
1518		if (l) {
1519			/* now use that to get a host */
1520			host = (struct host_decl *)0;
1521			host_hash_lookup (&host, host_hw_addr_hash,
1522					  l -> hardware_addr.hbuf,
1523					  l -> hardware_addr.hlen, MDL);
1524
1525			if (host && *lp && *lp != (omapi_object_t *)host) {
1526			    omapi_object_dereference (lp, MDL);
1527			    if (host)
1528				host_dereference (&host, MDL);
1529			    return DHCP_R_KEYCONFLICT;
1530			} else if (!host || (host -> flags &
1531					     HOST_DECL_DELETED)) {
1532			    if (host)
1533				host_dereference (&host, MDL);
1534			    if (!*lp)
1535				    return ISC_R_NOTFOUND;
1536			} else if (!*lp) {
1537				/* XXX fix so that hash lookup itself creates
1538				   XXX the reference. */
1539			    omapi_object_reference (lp, (omapi_object_t *)host,
1540						    MDL);
1541			    host_dereference (&host, MDL);
1542			}
1543			lease_dereference (&l, MDL);
1544		}
1545	}
1546
1547	/* Now look for a name. */
1548	status = omapi_get_value_str (ref, id, "name", &tv);
1549	if (status == ISC_R_SUCCESS) {
1550		host = (struct host_decl *)0;
1551		host_hash_lookup (&host, host_name_hash,
1552				  tv -> value -> u.buffer.value,
1553				  tv -> value -> u.buffer.len, MDL);
1554		omapi_value_dereference (&tv, MDL);
1555
1556		if (*lp && *lp != (omapi_object_t *)host) {
1557			omapi_object_dereference (lp, MDL);
1558			if (host)
1559			    host_dereference (&host, MDL);
1560			return DHCP_R_KEYCONFLICT;
1561		} else if (!host || (host -> flags & HOST_DECL_DELETED)) {
1562			if (host)
1563			    host_dereference (&host, MDL);
1564			return ISC_R_NOTFOUND;
1565		} else if (!*lp) {
1566			/* XXX fix so that hash lookup itself creates
1567			   XXX the reference. */
1568			omapi_object_reference (lp,
1569						(omapi_object_t *)host, MDL);
1570			host_dereference (&host, MDL);
1571		}
1572	}
1573
1574	/* If we get to here without finding a host, no valid key was
1575	   specified. */
1576	if (!*lp)
1577		return DHCP_R_NOKEYS;
1578	return ISC_R_SUCCESS;
1579}
1580
1581isc_result_t dhcp_host_create (omapi_object_t **lp,
1582			       omapi_object_t *id)
1583{
1584	struct host_decl *hp;
1585	isc_result_t status;
1586	hp = (struct host_decl *)0;
1587	status = host_allocate (&hp, MDL);
1588	if (status != ISC_R_SUCCESS)
1589		return status;
1590	group_reference (&hp -> group, root_group, MDL);
1591	hp -> flags = HOST_DECL_DYNAMIC;
1592	status = omapi_object_reference (lp, (omapi_object_t *)hp, MDL);
1593	host_dereference (&hp, MDL);
1594	return status;
1595}
1596
1597isc_result_t dhcp_host_remove (omapi_object_t *lp,
1598			       omapi_object_t *id)
1599{
1600	struct host_decl *hp;
1601	if (lp -> type != dhcp_type_host)
1602		return DHCP_R_INVALIDARG;
1603	hp = (struct host_decl *)lp;
1604
1605#ifdef DEBUG_OMAPI
1606	log_debug ("OMAPI delete host %s", hp -> name);
1607#endif
1608	delete_host (hp, 1);
1609	return ISC_R_SUCCESS;
1610}
1611
1612isc_result_t dhcp_pool_set_value  (omapi_object_t *h,
1613				   omapi_object_t *id,
1614				   omapi_data_string_t *name,
1615				   omapi_typed_data_t *value)
1616{
1617	/* h should point to (struct pool *) */
1618	isc_result_t status;
1619
1620	if (h -> type != dhcp_type_pool)
1621		return DHCP_R_INVALIDARG;
1622
1623	/* No values to set yet. */
1624
1625	/* Try to find some inner object that can take the value. */
1626	if (h -> inner && h -> inner -> type -> set_value) {
1627		status = ((*(h -> inner -> type -> set_value))
1628			  (h -> inner, id, name, value));
1629		if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED)
1630			return status;
1631	}
1632
1633	return DHCP_R_UNKNOWNATTRIBUTE;
1634}
1635
1636
1637isc_result_t dhcp_pool_get_value (omapi_object_t *h, omapi_object_t *id,
1638				  omapi_data_string_t *name,
1639				  omapi_value_t **value)
1640{
1641	/* h should point to (struct pool *) */
1642	isc_result_t status;
1643
1644	if (h -> type != dhcp_type_pool)
1645		return DHCP_R_INVALIDARG;
1646
1647	/* No values to get yet. */
1648
1649	/* Try to find some inner object that can provide the value. */
1650	if (h -> inner && h -> inner -> type -> get_value) {
1651		status = ((*(h -> inner -> type -> get_value))
1652			  (h -> inner, id, name, value));
1653		if (status == ISC_R_SUCCESS)
1654			return status;
1655	}
1656	return DHCP_R_UNKNOWNATTRIBUTE;
1657}
1658
1659isc_result_t dhcp_pool_destroy (omapi_object_t *h, const char *file, int line)
1660{
1661	struct permit *pc, *pn;
1662
1663	if (h -> type != dhcp_type_pool)
1664		return DHCP_R_INVALIDARG;
1665
1666	struct pool *pool = (struct pool *)h;
1667	if (pool -> next)
1668		pool_dereference (&pool -> next, file, line);
1669	if (pool -> group)
1670		group_dereference (&pool -> group, file, line);
1671	if (pool -> shared_network)
1672	    shared_network_dereference (&pool -> shared_network, file, line);
1673
1674	POOL_DESTROYP(&pool->active);
1675	POOL_DESTROYP(&pool->expired);
1676	POOL_DESTROYP(&pool->free);
1677	POOL_DESTROYP(&pool->backup);
1678	POOL_DESTROYP(&pool->abandoned);
1679	POOL_DESTROYP(&pool->reserved);
1680
1681#if defined (FAILOVER_PROTOCOL)
1682	if (pool -> failover_peer)
1683		dhcp_failover_state_dereference (&pool -> failover_peer,
1684						 file, line);
1685#endif
1686
1687	for (pc = pool -> permit_list; pc; pc = pn) {
1688		pn = pc -> next;
1689		free_permit (pc, file, line);
1690	}
1691	pool -> permit_list = (struct permit *)0;
1692
1693	for (pc = pool -> prohibit_list; pc; pc = pn) {
1694		pn = pc -> next;
1695		free_permit (pc, file, line);
1696	}
1697	pool -> prohibit_list = (struct permit *)0;
1698
1699	return ISC_R_SUCCESS;
1700}
1701
1702isc_result_t dhcp_pool_signal_handler (omapi_object_t *h,
1703				       const char *name, va_list ap)
1704{
1705	/* h should point to (struct pool *) */
1706	isc_result_t status;
1707
1708	if (h -> type != dhcp_type_pool)
1709		return DHCP_R_INVALIDARG;
1710
1711	/* Can't write pools yet. */
1712
1713	/* Try to find some inner object that can take the value. */
1714	if (h -> inner && h -> inner -> type -> signal_handler) {
1715		status = ((*(h -> inner -> type -> signal_handler))
1716			  (h -> inner, name, ap));
1717		if (status == ISC_R_SUCCESS)
1718			return status;
1719	}
1720
1721	return ISC_R_NOTFOUND;
1722}
1723
1724isc_result_t dhcp_pool_stuff_values (omapi_object_t *c,
1725				     omapi_object_t *id,
1726				     omapi_object_t *h)
1727{
1728	struct pool *pool;
1729	isc_result_t status;
1730
1731	if (h->type != dhcp_type_pool)
1732		return (DHCP_R_INVALIDARG);
1733	pool = (struct pool *)h;
1734
1735	/*
1736	 * I don't think we can actually find a pool yet
1737	 * but include the output of interesting values
1738	 * for when we do
1739	 */
1740	status = omapi_connection_put_named_uint32(c, "lease-count",
1741						   ((u_int32_t)
1742						    pool->lease_count));
1743	if (status != ISC_R_SUCCESS)
1744		return (status);
1745
1746	status = omapi_connection_put_named_uint32(c, "free-leases",
1747						   ((u_int32_t)
1748						    pool->free_leases));
1749	if (status != ISC_R_SUCCESS)
1750		return (status);
1751
1752	status = omapi_connection_put_named_uint32(c, "backup-leases",
1753						   ((u_int32_t)
1754						    pool->backup_leases));
1755	if (status != ISC_R_SUCCESS)
1756		return (status);
1757	/* we could add time stamps but lets wait on those */
1758
1759	/* Write out the inner object, if any. */
1760	if (h->inner && h->inner->type->stuff_values) {
1761		status = ((*(h->inner->type->stuff_values))
1762			  (c, id, h->inner));
1763		if (status == ISC_R_SUCCESS)
1764			return (status);
1765	}
1766
1767	return (ISC_R_SUCCESS);
1768}
1769
1770isc_result_t dhcp_pool_lookup (omapi_object_t **lp,
1771			       omapi_object_t *id, omapi_object_t *ref)
1772{
1773	/* Can't look up pools yet. */
1774
1775	/* If we get to here without finding a pool, no valid key was
1776	   specified. */
1777	if (!*lp)
1778		return DHCP_R_NOKEYS;
1779	return ISC_R_SUCCESS;
1780}
1781
1782isc_result_t dhcp_pool_create (omapi_object_t **lp,
1783			       omapi_object_t *id)
1784{
1785	return ISC_R_NOTIMPLEMENTED;
1786}
1787
1788isc_result_t dhcp_pool_remove (omapi_object_t *lp,
1789			       omapi_object_t *id)
1790{
1791	return ISC_R_NOTIMPLEMENTED;
1792}
1793
1794static isc_result_t
1795class_set_value (omapi_object_t *h,
1796		 omapi_object_t *id,
1797		 omapi_data_string_t *name,
1798		 omapi_typed_data_t *value)
1799{
1800	struct class *class;
1801	struct class *superclass = 0;
1802	isc_result_t status;
1803	int issubclass = (h -> type == dhcp_type_subclass);
1804
1805	class = (struct class *)h;
1806
1807	if (!omapi_ds_strcmp(name, "name")) {
1808		if (class->name)
1809			return ISC_R_EXISTS;
1810
1811		if (issubclass) {
1812			char tname[value->u.buffer.len + 1];
1813			memcpy(tname, value->u.buffer.value, value->u.buffer.len);
1814			tname[sizeof(tname)-1] = '\0';
1815			status = find_class(&superclass, tname, MDL);
1816
1817			if (status == ISC_R_NOTFOUND)
1818				return status;
1819
1820			if (class->superclass != NULL)
1821				class_dereference(&class->superclass, MDL);
1822			class_reference(&class->superclass, superclass, MDL);
1823
1824			if (class->group != NULL)
1825				group_dereference(&class->group, MDL);
1826			group_reference(&class->group, superclass->group, MDL);
1827
1828			class->lease_limit = superclass->lease_limit;
1829			if (class->lease_limit != 0) {
1830				class->billed_leases =
1831					dmalloc(class->lease_limit *
1832						sizeof(struct lease *),
1833						MDL);
1834				if (class->billed_leases == NULL) {
1835					return ISC_R_NOMEMORY;
1836				}
1837			}
1838
1839		} else if (value->type == omapi_datatype_data ||
1840			   value->type == omapi_datatype_string) {
1841			class->name = dmalloc(value->u.buffer.len + 1, MDL);
1842			if (!class->name)
1843				return ISC_R_NOMEMORY;
1844
1845			/* class->name is null-terminated from dmalloc() */
1846			memcpy(class->name, value->u.buffer.value,
1847			       value->u.buffer.len);
1848		} else
1849			return DHCP_R_INVALIDARG;
1850
1851		return ISC_R_SUCCESS;
1852	}
1853
1854
1855	if (issubclass && !omapi_ds_strcmp(name, "hashstring")) {
1856		if (class->hash_string.data)
1857			return ISC_R_EXISTS;
1858
1859		if (value->type == omapi_datatype_data ||
1860		    value->type == omapi_datatype_string) {
1861			if (!buffer_allocate(&class->hash_string.buffer,
1862					     value->u.buffer.len, MDL))
1863				return ISC_R_NOMEMORY;
1864			class->hash_string.data =
1865					class->hash_string.buffer->data;
1866			memcpy(class->hash_string.buffer->data,
1867			       value->u.buffer.value, value->u.buffer.len);
1868			class->hash_string.len = value->u.buffer.len;
1869		} else
1870			return DHCP_R_INVALIDARG;
1871
1872		return ISC_R_SUCCESS;
1873	}
1874
1875	if (!omapi_ds_strcmp(name, "group")) {
1876		if (value->type == omapi_datatype_data ||
1877		    value->type == omapi_datatype_string) {
1878			struct group_object *group = NULL;
1879
1880			group_hash_lookup(&group, group_name_hash,
1881					  (char *)value->u.buffer.value,
1882					  value->u.buffer.len, MDL);
1883			if (!group || (group->flags & GROUP_OBJECT_DELETED))
1884				return ISC_R_NOTFOUND;
1885			if (class->group)
1886				group_dereference(&class->group, MDL);
1887			group_reference(&class->group, group->group, MDL);
1888			group_object_dereference(&group, MDL);
1889		} else
1890			return DHCP_R_INVALIDARG;
1891
1892		return ISC_R_SUCCESS;
1893	}
1894
1895
1896	/* note we do not support full expressions via omapi because the
1897	   expressions parser needs to be re-done to support parsing from
1898	   strings and not just files. */
1899
1900	if (!omapi_ds_strcmp(name, "match")) {
1901		if (value->type == omapi_datatype_data ||
1902		    value->type == omapi_datatype_string) {
1903			unsigned minlen = (value->u.buffer.len > 8 ?
1904						8 : value->u.buffer.len);
1905
1906			if (!strncmp("hardware",
1907				     (char *)value->u.buffer.value, minlen))
1908			{
1909				if (!expression_allocate(&class->submatch, MDL))
1910					return ISC_R_NOMEMORY;
1911
1912				class->submatch->op = expr_hardware;
1913			} else
1914				return DHCP_R_INVALIDARG;
1915		} else
1916			return DHCP_R_INVALIDARG;
1917
1918		return ISC_R_SUCCESS;
1919	}
1920
1921
1922	if (!omapi_ds_strcmp(name, "option")) {
1923		if (value->type == omapi_datatype_data ||
1924		    value->type == omapi_datatype_string) {
1925			/* XXXJAB support 'options' here. */
1926			/* XXXJAB specifically 'bootfile-name' */
1927			return DHCP_R_INVALIDARG; /* XXX tmp */
1928		} else
1929			return DHCP_R_INVALIDARG;
1930
1931		/*
1932		 * Currently no way to get here, if we update the above
1933		 * code so that we do get here this return needs to be
1934		 * uncommented.
1935		 * return ISC_R_SUCCESS;
1936		 */
1937	}
1938
1939
1940	/* Try to find some inner object that can take the value. */
1941	if (h->inner && h->inner->type->set_value) {
1942		status = ((*(h->inner->type->set_value))
1943			  (h->inner, id, name, value));
1944		if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED)
1945			return status;
1946	}
1947
1948	return DHCP_R_UNKNOWNATTRIBUTE;
1949}
1950
1951
1952
1953isc_result_t dhcp_class_set_value  (omapi_object_t *h,
1954				    omapi_object_t *id,
1955				    omapi_data_string_t *name,
1956				    omapi_typed_data_t *value)
1957{
1958	if (h -> type != dhcp_type_class)
1959		return DHCP_R_INVALIDARG;
1960
1961	return class_set_value(h, id, name, value);
1962}
1963
1964isc_result_t dhcp_class_get_value (omapi_object_t *h, omapi_object_t *id,
1965				   omapi_data_string_t *name,
1966				   omapi_value_t **value)
1967{
1968	struct class *class;
1969	isc_result_t status;
1970
1971	if (h -> type != dhcp_type_class)
1972		return DHCP_R_INVALIDARG;
1973	class = (struct class *)h;
1974
1975	if (!omapi_ds_strcmp (name, "name"))
1976		return omapi_make_string_value (value, name, class -> name,
1977						MDL);
1978
1979	/* Try to find some inner object that can provide the value. */
1980	if (h -> inner && h -> inner -> type -> get_value) {
1981		status = ((*(h -> inner -> type -> get_value))
1982			  (h -> inner, id, name, value));
1983		if (status == ISC_R_SUCCESS)
1984			return status;
1985	}
1986	return DHCP_R_UNKNOWNATTRIBUTE;
1987}
1988
1989isc_result_t dhcp_class_destroy (omapi_object_t *h, const char *file, int line)
1990{
1991
1992	if (h -> type != dhcp_type_class && h -> type != dhcp_type_subclass)
1993		return DHCP_R_INVALIDARG;
1994	struct class *class = (struct class *)h;
1995
1996	if (class -> nic)
1997		class_dereference (&class -> nic, file, line);
1998	if (class -> superclass)
1999		class_dereference (&class -> superclass, file, line);
2000	if (class -> name) {
2001		dfree (class -> name, file, line);
2002		class -> name = (char *)0;
2003	}
2004	if (class -> billed_leases) {
2005		int i;
2006		for (i = 0; i < class -> lease_limit; i++) {
2007			if (class -> billed_leases [i]) {
2008				lease_dereference (&class -> billed_leases [i],
2009						   file, line);
2010			}
2011		}
2012		dfree (class -> billed_leases, file, line);
2013		class -> billed_leases = (struct lease **)0;
2014	}
2015	if (class -> hash) {
2016		class_free_hash_table (&class -> hash, file, line);
2017		class -> hash = (class_hash_t *)0;
2018	}
2019	data_string_forget (&class -> hash_string, file, line);
2020
2021	if (class -> expr)
2022		expression_dereference (&class -> expr, file, line);
2023	if (class -> submatch)
2024		expression_dereference (&class -> submatch, file, line);
2025	if (class -> group)
2026		group_dereference (&class -> group, file, line);
2027	if (class -> statements)
2028		executable_statement_dereference (&class -> statements,
2029						  file, line);
2030	if (class -> superclass)
2031		class_dereference (&class -> superclass, file, line);
2032
2033	return ISC_R_SUCCESS;
2034}
2035
2036static isc_result_t
2037class_signal_handler(omapi_object_t *h,
2038		     const char *name, va_list ap)
2039{
2040	struct class *class = (struct class *)h;
2041	isc_result_t status;
2042	int updatep = 0;
2043	int issubclass;
2044
2045	issubclass = (h->type == dhcp_type_subclass);
2046
2047	if (!strcmp (name, "updated")) {
2048
2049		if (!issubclass) {
2050			if (class->name == 0 || strlen(class->name) == 0) {
2051				return DHCP_R_INVALIDARG;
2052			}
2053		} else {
2054			if (class->superclass == 0) {
2055				return DHCP_R_INVALIDARG; /* didn't give name */
2056			}
2057
2058			if (class->hash_string.data == NULL) {
2059				return DHCP_R_INVALIDARG;
2060			}
2061		}
2062
2063
2064		if (issubclass) {
2065			if (!class->superclass->hash)
2066				class_new_hash(&class->superclass->hash,
2067					       SCLASS_HASH_SIZE, MDL);
2068
2069			class_hash_add(class->superclass->hash,
2070				       (const char *)class->hash_string.data,
2071				       class->hash_string.len,
2072				       (void *)class, MDL);
2073		}
2074
2075#ifdef DEBUG_OMAPI
2076		if (issubclass) {
2077			log_debug ("OMAPI added subclass %s",
2078				   class->superclass->name);
2079		} else {
2080			log_debug ("OMAPI added class %s", class->name);
2081		}
2082#endif
2083
2084		status = enter_class (class, 1, 1);
2085		if (status != ISC_R_SUCCESS)
2086			return status;
2087		updatep = 1;
2088	}
2089
2090	/* Try to find some inner object that can take the value. */
2091	if (h->inner && h->inner->type->signal_handler) {
2092		status = ((*(h->inner->type->signal_handler))
2093			  (h->inner, name, ap));
2094		if (status == ISC_R_SUCCESS)
2095			return status;
2096	}
2097
2098	if (updatep)
2099		return ISC_R_SUCCESS;
2100
2101	return ISC_R_NOTFOUND;
2102}
2103
2104
2105isc_result_t dhcp_class_signal_handler (omapi_object_t *h,
2106					const char *name, va_list ap)
2107{
2108	if (h -> type != dhcp_type_class)
2109		return DHCP_R_INVALIDARG;
2110
2111	return class_signal_handler(h, name, ap);
2112}
2113
2114
2115/*
2116 * Routine to put out generic class & subclass information
2117 */
2118static isc_result_t class_stuff_values (omapi_object_t *c,
2119				 omapi_object_t *id,
2120				 omapi_object_t *h)
2121{
2122	struct class *class;
2123	isc_result_t status;
2124
2125	class = (struct class *)h;
2126
2127	status = omapi_connection_put_named_uint32(c, "lease-limit",
2128						   ((u_int32_t)
2129						    class->lease_limit));
2130	if (status != ISC_R_SUCCESS)
2131		return (status);
2132
2133	status = omapi_connection_put_named_uint32(c, "leases-used",
2134						   ((u_int32_t)
2135						    class->leases_consumed));
2136	if (status != ISC_R_SUCCESS)
2137		return (status);
2138
2139	/* Write out the inner object, if any. */
2140	if (h->inner && h->inner->type->stuff_values) {
2141		status = ((*(h->inner->type->stuff_values))
2142			  (c, id, h->inner));
2143		if (status == ISC_R_SUCCESS)
2144			return (status);
2145	}
2146
2147	return (ISC_R_SUCCESS);
2148}
2149
2150
2151isc_result_t dhcp_class_stuff_values (omapi_object_t *c,
2152				      omapi_object_t *id,
2153				      omapi_object_t *h)
2154{
2155	if (h->type != dhcp_type_class)
2156		return (DHCP_R_INVALIDARG);
2157
2158	/* add any class specific items here */
2159
2160	return (class_stuff_values(c, id, h));
2161}
2162
2163static isc_result_t class_lookup (omapi_object_t **lp,
2164				  omapi_object_t *id, omapi_object_t *ref,
2165				  omapi_object_type_t *typewanted)
2166{
2167	omapi_value_t *nv = NULL;
2168	omapi_value_t *hv = NULL;
2169	isc_result_t status;
2170	struct class *class = 0;
2171	struct class *subclass = 0;
2172
2173	*lp = NULL;
2174
2175	if (ref == NULL)
2176		return (DHCP_R_NOKEYS);
2177
2178	/* see if we have a name */
2179	status = omapi_get_value_str(ref, id, "name", &nv);
2180	if (status == ISC_R_SUCCESS) {
2181		char *name = dmalloc(nv->value->u.buffer.len + 1, MDL);
2182		if (name == NULL)
2183			return (ISC_R_NOMEMORY);
2184		memcpy (name,
2185			nv->value->u.buffer.value,
2186			nv->value->u.buffer.len);
2187
2188		omapi_value_dereference(&nv, MDL);
2189
2190		find_class(&class, name, MDL);
2191
2192		dfree(name, MDL);
2193
2194		if (class == NULL) {
2195			return (ISC_R_NOTFOUND);
2196		}
2197
2198		if (typewanted == dhcp_type_subclass) {
2199			status = omapi_get_value_str(ref, id,
2200						     "hashstring", &hv);
2201			if (status != ISC_R_SUCCESS) {
2202				class_dereference(&class, MDL);
2203				return (DHCP_R_NOKEYS);
2204			}
2205
2206			if (hv->value->type != omapi_datatype_data &&
2207			    hv->value->type != omapi_datatype_string) {
2208				class_dereference(&class, MDL);
2209				omapi_value_dereference(&hv, MDL);
2210				return (DHCP_R_NOKEYS);
2211			}
2212
2213			class_hash_lookup(&subclass, class->hash,
2214					  (const char *)
2215					  hv->value->u.buffer.value,
2216					  hv->value->u.buffer.len, MDL);
2217
2218			omapi_value_dereference(&hv, MDL);
2219
2220			class_dereference(&class, MDL);
2221
2222			if (subclass == NULL) {
2223				return (ISC_R_NOTFOUND);
2224			}
2225
2226			class_reference(&class, subclass, MDL);
2227			class_dereference(&subclass, MDL);
2228		}
2229
2230		/* Don't return the object if the type is wrong. */
2231		if (class->type != typewanted) {
2232			class_dereference(&class, MDL);
2233			return (DHCP_R_INVALIDARG);
2234		}
2235
2236		if (class->flags & CLASS_DECL_DELETED) {
2237			class_dereference(&class, MDL);
2238			return (ISC_R_NOTFOUND);
2239		}
2240
2241		omapi_object_reference(lp, (omapi_object_t *)class, MDL);
2242		class_dereference(&class, MDL);
2243
2244		return (ISC_R_SUCCESS);
2245	}
2246
2247	return (DHCP_R_NOKEYS);
2248}
2249
2250
2251isc_result_t dhcp_class_lookup (omapi_object_t **lp,
2252				omapi_object_t *id, omapi_object_t *ref)
2253{
2254	return class_lookup(lp, id, ref, dhcp_type_class);
2255}
2256
2257isc_result_t dhcp_class_create (omapi_object_t **lp,
2258				omapi_object_t *id)
2259{
2260	struct class *cp = 0;
2261	isc_result_t status;
2262
2263	status = class_allocate(&cp, MDL);
2264	if (status != ISC_R_SUCCESS)
2265		return (status);
2266
2267	if (clone_group(&cp->group, root_group, MDL) == 0)
2268		return (ISC_R_NOMEMORY);
2269
2270	cp->flags = CLASS_DECL_DYNAMIC;
2271	status = omapi_object_reference(lp, (omapi_object_t *)cp, MDL);
2272	class_dereference(&cp, MDL);
2273	return (status);
2274}
2275
2276isc_result_t dhcp_class_remove (omapi_object_t *lp,
2277				omapi_object_t *id)
2278{
2279	struct class *cp;
2280	if (lp -> type != dhcp_type_class)
2281		return DHCP_R_INVALIDARG;
2282	cp = (struct class *)lp;
2283
2284#ifdef DEBUG_OMAPI
2285	log_debug ("OMAPI delete class %s", cp -> name);
2286#endif
2287
2288	delete_class (cp, 1);
2289	return ISC_R_SUCCESS;
2290}
2291
2292isc_result_t dhcp_subclass_set_value  (omapi_object_t *h,
2293				       omapi_object_t *id,
2294				       omapi_data_string_t *name,
2295				       omapi_typed_data_t *value)
2296{
2297	if (h -> type != dhcp_type_subclass)
2298		return DHCP_R_INVALIDARG;
2299
2300	return class_set_value(h, id, name, value);
2301}
2302
2303
2304isc_result_t dhcp_subclass_get_value (omapi_object_t *h, omapi_object_t *id,
2305				      omapi_data_string_t *name,
2306				      omapi_value_t **value)
2307{
2308	struct class *subclass;
2309	isc_result_t status;
2310
2311	if (h -> type != dhcp_type_class)
2312		return DHCP_R_INVALIDARG;
2313	subclass = (struct class *)h;
2314	if (subclass -> name != 0)
2315		return DHCP_R_INVALIDARG;
2316
2317	/* XXXJAB No values to get yet. */
2318
2319	/* Try to find some inner object that can provide the value. */
2320	if (h -> inner && h -> inner -> type -> get_value) {
2321		status = ((*(h -> inner -> type -> get_value))
2322			  (h -> inner, id, name, value));
2323		if (status == ISC_R_SUCCESS)
2324			return status;
2325	}
2326	return DHCP_R_UNKNOWNATTRIBUTE;
2327}
2328
2329isc_result_t dhcp_subclass_signal_handler (omapi_object_t *h,
2330					   const char *name, va_list ap)
2331{
2332	if (h -> type != dhcp_type_subclass)
2333		return DHCP_R_INVALIDARG;
2334
2335	return class_signal_handler(h, name, ap);
2336}
2337
2338
2339isc_result_t dhcp_subclass_stuff_values (omapi_object_t *c,
2340					 omapi_object_t *id,
2341					 omapi_object_t *h)
2342{
2343	struct class *subclass;
2344
2345	if (h->type != dhcp_type_subclass)
2346		return (DHCP_R_INVALIDARG);
2347	subclass = (struct class *)h;
2348	if (subclass->name != 0)
2349		return (DHCP_R_INVALIDARG);
2350
2351	/* add any subclass specific items here */
2352
2353	return (class_stuff_values(c, id, h));
2354}
2355
2356isc_result_t dhcp_subclass_lookup (omapi_object_t **lp,
2357				   omapi_object_t *id, omapi_object_t *ref)
2358{
2359	return class_lookup(lp, id, ref, dhcp_type_subclass);
2360}
2361
2362
2363
2364
2365isc_result_t dhcp_subclass_create (omapi_object_t **lp,
2366				   omapi_object_t *id)
2367{
2368	struct class *cp = 0;
2369	isc_result_t status;
2370
2371	status = subclass_allocate(&cp, MDL);
2372	if (status != ISC_R_SUCCESS)
2373		return status;
2374	group_reference (&cp->group, root_group, MDL);
2375
2376	cp->flags = CLASS_DECL_DYNAMIC;
2377
2378	status = omapi_object_reference (lp, (omapi_object_t *)cp, MDL);
2379	subclass_dereference (&cp, MDL);
2380	return status;
2381}
2382
2383isc_result_t dhcp_subclass_remove (omapi_object_t *lp,
2384				   omapi_object_t *id)
2385{
2386	struct class *cp;
2387	if (lp -> type != dhcp_type_subclass)
2388		return DHCP_R_INVALIDARG;
2389	cp = (struct class *)lp;
2390
2391#ifdef DEBUG_OMAPI
2392	log_debug ("OMAPI delete subclass %s", cp -> name);
2393#endif
2394
2395	delete_class (cp, 1);
2396
2397	return ISC_R_SUCCESS;
2398}
2399
2400isc_result_t binding_scope_set_value (struct binding_scope *scope, int createp,
2401				      omapi_data_string_t *name,
2402				      omapi_typed_data_t *value)
2403{
2404	struct binding *bp;
2405	char *nname;
2406	struct binding_value *nv;
2407	nname = dmalloc (name -> len + 1, MDL);
2408	if (!nname)
2409		return ISC_R_NOMEMORY;
2410	memcpy (nname, name -> value, name -> len);
2411	nname [name -> len] = 0;
2412	bp = find_binding (scope, nname);
2413	if (!bp && !createp) {
2414		dfree (nname, MDL);
2415		return DHCP_R_UNKNOWNATTRIBUTE;
2416	}
2417	if (!value) {
2418		dfree (nname, MDL);
2419		if (!bp)
2420			return DHCP_R_UNKNOWNATTRIBUTE;
2421		binding_value_dereference (&bp -> value, MDL);
2422		return ISC_R_SUCCESS;
2423	}
2424
2425	nv = (struct binding_value *)0;
2426	if (!binding_value_allocate (&nv, MDL)) {
2427		dfree (nname, MDL);
2428		return ISC_R_NOMEMORY;
2429	}
2430	switch (value -> type) {
2431	      case omapi_datatype_int:
2432		nv -> type = binding_numeric;
2433		nv -> value.intval = value -> u.integer;
2434		break;
2435
2436	      case omapi_datatype_string:
2437	      case omapi_datatype_data:
2438		if (!buffer_allocate (&nv -> value.data.buffer,
2439				      value -> u.buffer.len, MDL)) {
2440			binding_value_dereference (&nv, MDL);
2441			dfree (nname, MDL);
2442			return ISC_R_NOMEMORY;
2443		}
2444		memcpy (&nv -> value.data.buffer -> data [1],
2445			value -> u.buffer.value, value -> u.buffer.len);
2446		nv -> value.data.len = value -> u.buffer.len;
2447		break;
2448
2449	      case omapi_datatype_object:
2450		binding_value_dereference (&nv, MDL);
2451		dfree (nname, MDL);
2452		return DHCP_R_INVALIDARG;
2453	}
2454
2455	if (!bp) {
2456		bp = dmalloc (sizeof *bp, MDL);
2457		if (!bp) {
2458			binding_value_dereference (&nv, MDL);
2459			dfree (nname, MDL);
2460			return ISC_R_NOMEMORY;
2461		}
2462		memset (bp, 0, sizeof *bp);
2463		bp -> name = nname;
2464		bp -> next = scope -> bindings;
2465		scope -> bindings = bp;
2466	} else {
2467		if (bp -> value)
2468			binding_value_dereference (&bp -> value, MDL);
2469		dfree (nname, MDL);
2470	}
2471	binding_value_reference (&bp -> value, nv, MDL);
2472	binding_value_dereference (&nv, MDL);
2473	return ISC_R_SUCCESS;
2474}
2475
2476isc_result_t binding_scope_get_value (omapi_value_t **value,
2477				      struct binding_scope *scope,
2478				      omapi_data_string_t *name)
2479{
2480	struct binding *bp;
2481	omapi_typed_data_t *td;
2482	isc_result_t status;
2483	char *nname;
2484	nname = dmalloc (name -> len + 1, MDL);
2485	if (!nname)
2486		return ISC_R_NOMEMORY;
2487	memcpy (nname, name -> value, name -> len);
2488	nname [name -> len] = 0;
2489	bp = find_binding (scope, nname);
2490	dfree (nname, MDL);
2491	if (!bp)
2492		return DHCP_R_UNKNOWNATTRIBUTE;
2493	if (!bp -> value)
2494		return DHCP_R_UNKNOWNATTRIBUTE;
2495
2496	switch (bp -> value -> type) {
2497	      case binding_boolean:
2498		td = (omapi_typed_data_t *)0;
2499		status = omapi_typed_data_new (MDL, &td, omapi_datatype_int,
2500					       bp -> value -> value.boolean);
2501		break;
2502
2503	      case binding_numeric:
2504		td = (omapi_typed_data_t *)0;
2505		status = omapi_typed_data_new (MDL, &td, omapi_datatype_int,
2506					       (int)
2507					       bp -> value -> value.intval);
2508		break;
2509
2510	      case binding_data:
2511		td = (omapi_typed_data_t *)0;
2512		status = omapi_typed_data_new (MDL, &td, omapi_datatype_data,
2513					       bp -> value -> value.data.len);
2514		if (status != ISC_R_SUCCESS)
2515			return status;
2516		memcpy (&td -> u.buffer.value [0],
2517			bp -> value -> value.data.data,
2518			bp -> value -> value.data.len);
2519		break;
2520
2521		/* Can't return values for these two (yet?). */
2522	      case binding_dns:
2523	      case binding_function:
2524		return DHCP_R_INVALIDARG;
2525
2526	      default:
2527		log_fatal ("Impossible case at %s:%d.", MDL);
2528		return ISC_R_FAILURE;
2529	}
2530
2531	if (status != ISC_R_SUCCESS)
2532		return status;
2533	status = omapi_value_new (value, MDL);
2534	if (status != ISC_R_SUCCESS) {
2535		omapi_typed_data_dereference (&td, MDL);
2536		return status;
2537	}
2538
2539	omapi_data_string_reference (&(*value) -> name, name, MDL);
2540	omapi_typed_data_reference (&(*value) -> value, td, MDL);
2541	omapi_typed_data_dereference (&td, MDL);
2542
2543	return ISC_R_SUCCESS;
2544}
2545
2546isc_result_t binding_scope_stuff_values (omapi_object_t *c,
2547					 struct binding_scope *scope)
2548{
2549	struct binding *bp;
2550	unsigned len;
2551	isc_result_t status;
2552
2553	for (bp = scope -> bindings; bp; bp = bp -> next) {
2554	    if (bp -> value) {
2555		if (bp -> value -> type == binding_dns ||
2556		    bp -> value -> type == binding_function)
2557			continue;
2558
2559		/* Stuff the name. */
2560		len = strlen (bp -> name);
2561		status = omapi_connection_put_uint16 (c, len);
2562		if (status != ISC_R_SUCCESS)
2563		    return status;
2564		status = omapi_connection_copyin (c,
2565						  (unsigned char *)bp -> name,
2566						  len);
2567		if (status != ISC_R_SUCCESS)
2568			return status;
2569
2570		switch (bp -> value -> type) {
2571		  case binding_boolean:
2572		    status = omapi_connection_put_uint32 (c,
2573							  sizeof (u_int32_t));
2574		    if (status != ISC_R_SUCCESS)
2575			return status;
2576		    status = (omapi_connection_put_uint32
2577			      (c,
2578			       ((u_int32_t)(bp -> value -> value.boolean))));
2579		    if (status != ISC_R_SUCCESS)
2580			    return status;
2581		    break;
2582
2583		  case binding_data:
2584		    status = (omapi_connection_put_uint32
2585			      (c, bp -> value -> value.data.len));
2586		    if (status != ISC_R_SUCCESS)
2587			return status;
2588		    if (bp -> value -> value.data.len) {
2589			status = (omapi_connection_copyin
2590				  (c, bp -> value -> value.data.data,
2591				   bp -> value -> value.data.len));
2592			if (status != ISC_R_SUCCESS)
2593			    return status;
2594		    }
2595		    break;
2596
2597		  case binding_numeric:
2598		    status = (omapi_connection_put_uint32
2599			      (c, sizeof (u_int32_t)));
2600		    if (status != ISC_R_SUCCESS)
2601			    return status;
2602		    status = (omapi_connection_put_uint32
2603			      (c, ((u_int32_t)
2604				   (bp -> value -> value.intval))));
2605		    if (status != ISC_R_SUCCESS)
2606			    return status;
2607		    break;
2608
2609
2610		    /* NOTREACHED */
2611		  case binding_dns:
2612		  case binding_function:
2613		    break;
2614		}
2615	    }
2616	}
2617	return ISC_R_SUCCESS;
2618}
2619
2620/* vim: set tabstop=8: */
2621