xref: /netbsd/external/mpl/dhcp/dist/server/omapi.c (revision 13df4856)
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 
44 static isc_result_t class_lookup (omapi_object_t **,
45 				  omapi_object_t *, omapi_object_t *,
46 				  omapi_object_type_t *);
47 
48 static isc_result_t update_lease_flags(struct lease* lease,
49 				       omapi_typed_data_t *value);
50 
51 omapi_object_type_t *dhcp_type_lease;
52 omapi_object_type_t *dhcp_type_pool;
53 omapi_object_type_t *dhcp_type_class;
54 omapi_object_type_t *dhcp_type_subclass;
55 omapi_object_type_t *dhcp_type_host;
56 #if defined (FAILOVER_PROTOCOL)
57 omapi_object_type_t *dhcp_type_failover_state;
58 omapi_object_type_t *dhcp_type_failover_link;
59 omapi_object_type_t *dhcp_type_failover_listener;
60 #endif
61 
dhcp_db_objects_setup()62 void 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 
dhcp_lease_set_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_typed_data_t * value)205 isc_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  */
update_lease_flags(struct lease * lease,omapi_typed_data_t * value)335 static 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 
dhcp_lease_get_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_value_t ** value)396 isc_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 
dhcp_lease_destroy(omapi_object_t * h,const char * file,int line)472 isc_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 
dhcp_lease_signal_handler(omapi_object_t * h,const char * name,va_list ap)546 isc_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 
dhcp_lease_stuff_values(omapi_object_t * c,omapi_object_t * id,omapi_object_t * h)568 isc_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 
dhcp_lease_lookup(omapi_object_t ** lp,omapi_object_t * id,omapi_object_t * ref)753 isc_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 
dhcp_lease_create(omapi_object_t ** lp,omapi_object_t * id)919 isc_result_t dhcp_lease_create (omapi_object_t **lp,
920 				omapi_object_t *id)
921 {
922 	return ISC_R_NOTIMPLEMENTED;
923 }
924 
dhcp_lease_remove(omapi_object_t * lp,omapi_object_t * id)925 isc_result_t dhcp_lease_remove (omapi_object_t *lp,
926 				omapi_object_t *id)
927 {
928 	return ISC_R_NOTIMPLEMENTED;
929 }
930 
dhcp_host_set_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_typed_data_t * value)931 isc_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 
dhcp_host_get_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_value_t ** value)1126 isc_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 
dhcp_host_destroy(omapi_object_t * h,const char * file,int line)1195 isc_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 
dhcp_host_signal_handler(omapi_object_t * h,const char * name,va_list ap)1223 isc_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 
dhcp_host_stuff_values(omapi_object_t * c,omapi_object_t * id,omapi_object_t * h)1271 isc_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 
dhcp_host_lookup(omapi_object_t ** lp,omapi_object_t * id,omapi_object_t * ref)1374 isc_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 
dhcp_host_create(omapi_object_t ** lp,omapi_object_t * id)1581 isc_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 
dhcp_host_remove(omapi_object_t * lp,omapi_object_t * id)1597 isc_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 
dhcp_pool_set_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_typed_data_t * value)1612 isc_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 
dhcp_pool_get_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_value_t ** value)1637 isc_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 
dhcp_pool_destroy(omapi_object_t * h,const char * file,int line)1659 isc_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 
dhcp_pool_signal_handler(omapi_object_t * h,const char * name,va_list ap)1702 isc_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 
dhcp_pool_stuff_values(omapi_object_t * c,omapi_object_t * id,omapi_object_t * h)1724 isc_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 
dhcp_pool_lookup(omapi_object_t ** lp,omapi_object_t * id,omapi_object_t * ref)1770 isc_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 
dhcp_pool_create(omapi_object_t ** lp,omapi_object_t * id)1782 isc_result_t dhcp_pool_create (omapi_object_t **lp,
1783 			       omapi_object_t *id)
1784 {
1785 	return ISC_R_NOTIMPLEMENTED;
1786 }
1787 
dhcp_pool_remove(omapi_object_t * lp,omapi_object_t * id)1788 isc_result_t dhcp_pool_remove (omapi_object_t *lp,
1789 			       omapi_object_t *id)
1790 {
1791 	return ISC_R_NOTIMPLEMENTED;
1792 }
1793 
1794 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)1795 class_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 
dhcp_class_set_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_typed_data_t * value)1953 isc_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 
dhcp_class_get_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_value_t ** value)1964 isc_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 
dhcp_class_destroy(omapi_object_t * h,const char * file,int line)1989 isc_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 
2036 static isc_result_t
class_signal_handler(omapi_object_t * h,const char * name,va_list ap)2037 class_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 
dhcp_class_signal_handler(omapi_object_t * h,const char * name,va_list ap)2105 isc_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  */
class_stuff_values(omapi_object_t * c,omapi_object_t * id,omapi_object_t * h)2118 static 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 
dhcp_class_stuff_values(omapi_object_t * c,omapi_object_t * id,omapi_object_t * h)2151 isc_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 
class_lookup(omapi_object_t ** lp,omapi_object_t * id,omapi_object_t * ref,omapi_object_type_t * typewanted)2163 static 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 
dhcp_class_lookup(omapi_object_t ** lp,omapi_object_t * id,omapi_object_t * ref)2251 isc_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 
dhcp_class_create(omapi_object_t ** lp,omapi_object_t * id)2257 isc_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 
dhcp_class_remove(omapi_object_t * lp,omapi_object_t * id)2276 isc_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 
dhcp_subclass_set_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_typed_data_t * value)2292 isc_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 
dhcp_subclass_get_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_value_t ** value)2304 isc_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 
dhcp_subclass_signal_handler(omapi_object_t * h,const char * name,va_list ap)2329 isc_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 
dhcp_subclass_stuff_values(omapi_object_t * c,omapi_object_t * id,omapi_object_t * h)2339 isc_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 
dhcp_subclass_lookup(omapi_object_t ** lp,omapi_object_t * id,omapi_object_t * ref)2356 isc_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 
dhcp_subclass_create(omapi_object_t ** lp,omapi_object_t * id)2365 isc_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 
dhcp_subclass_remove(omapi_object_t * lp,omapi_object_t * id)2383 isc_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 
binding_scope_set_value(struct binding_scope * scope,int createp,omapi_data_string_t * name,omapi_typed_data_t * value)2400 isc_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 
binding_scope_get_value(omapi_value_t ** value,struct binding_scope * scope,omapi_data_string_t * name)2476 isc_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 
binding_scope_stuff_values(omapi_object_t * c,struct binding_scope * scope)2546 isc_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