Flesh out BUF_CMD_FLUSH support.
[dragonfly.git] / contrib / dhcp-3.0 / server / omapi.c
1 /* omapi.c
2
3    OMAPI object interfaces for the DHCP server. */
4
5 /*
6  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1999-2003 by Internet Software Consortium
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *
21  *   Internet Systems Consortium, Inc.
22  *   950 Charter Street
23  *   Redwood City, CA 94063
24  *   <info@isc.org>
25  *   http://www.isc.org/
26  *
27  * This software has been written for Internet Systems Consortium
28  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29  * To learn more about Internet Systems Consortium, see
30  * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
31  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
32  * ``http://www.nominum.com''.
33  */
34
35 /* Many, many thanks to Brian Murrell and BCtel for this code - BCtel
36    provided the funding that resulted in this code and the entire
37    OMAPI support library being written, and Brian helped brainstorm
38    and refine the requirements.  To the extent that this code is
39    useful, you have Brian and BCtel to thank.  Any limitations in the
40    code are a result of mistakes on my part.  -- Ted Lemon */
41
42 #ifndef lint
43 static char copyright[] =
44 "$Id: omapi.c,v 1.46.2.19 2004/11/24 17:39:19 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium.  All rights reserved.\n";
45 #endif /* not lint */
46
47 #include "dhcpd.h"
48 #include <omapip/omapip_p.h>
49
50 omapi_object_type_t *dhcp_type_lease;
51 omapi_object_type_t *dhcp_type_pool;
52 omapi_object_type_t *dhcp_type_class;
53 omapi_object_type_t *dhcp_type_subclass;
54 omapi_object_type_t *dhcp_type_host;
55 #if defined (FAILOVER_PROTOCOL)
56 omapi_object_type_t *dhcp_type_failover_state;
57 omapi_object_type_t *dhcp_type_failover_link;
58 omapi_object_type_t *dhcp_type_failover_listener;
59 #endif
60
61 void dhcp_db_objects_setup ()
62 {
63         isc_result_t status;
64
65         status = omapi_object_type_register (&dhcp_type_lease,
66                                              "lease",
67                                              dhcp_lease_set_value,
68                                              dhcp_lease_get_value,
69                                              dhcp_lease_destroy,
70                                              dhcp_lease_signal_handler,
71                                              dhcp_lease_stuff_values,
72                                              dhcp_lease_lookup, 
73                                              dhcp_lease_create,
74                                              dhcp_lease_remove,
75 #if defined (COMPACT_LEASES)
76                                              dhcp_lease_free,
77                                              dhcp_lease_get,
78 #else
79                                              0, 0,
80 #endif
81                                              0,
82                                              sizeof (struct lease),
83                                              0, RC_LEASE);
84         if (status != ISC_R_SUCCESS)
85                 log_fatal ("Can't register lease object type: %s",
86                            isc_result_totext (status));
87
88         status = omapi_object_type_register (&dhcp_type_class,
89                                              "class",
90                                              dhcp_class_set_value,
91                                              dhcp_class_get_value,
92                                              dhcp_class_destroy,
93                                              dhcp_class_signal_handler,
94                                              dhcp_class_stuff_values,
95                                              dhcp_class_lookup, 
96                                              dhcp_class_create,
97                                              dhcp_class_remove, 0, 0, 0,
98                                              sizeof (struct class), 0,
99                                              RC_MISC);
100         if (status != ISC_R_SUCCESS)
101                 log_fatal ("Can't register class object type: %s",
102                            isc_result_totext (status));
103
104         status = omapi_object_type_register (&dhcp_type_subclass,
105                                              "subclass",
106                                              dhcp_subclass_set_value,
107                                              dhcp_subclass_get_value,
108                                              dhcp_class_destroy,
109                                              dhcp_subclass_signal_handler,
110                                              dhcp_subclass_stuff_values,
111                                              dhcp_subclass_lookup, 
112                                              dhcp_subclass_create,
113                                              dhcp_subclass_remove, 0, 0, 0,
114                                              sizeof (struct class), 0, RC_MISC);
115         if (status != ISC_R_SUCCESS)
116                 log_fatal ("Can't register subclass object type: %s",
117                            isc_result_totext (status));
118
119         status = omapi_object_type_register (&dhcp_type_pool,
120                                              "pool",
121                                              dhcp_pool_set_value,
122                                              dhcp_pool_get_value,
123                                              dhcp_pool_destroy,
124                                              dhcp_pool_signal_handler,
125                                              dhcp_pool_stuff_values,
126                                              dhcp_pool_lookup, 
127                                              dhcp_pool_create,
128                                              dhcp_pool_remove, 0, 0, 0,
129                                              sizeof (struct pool), 0, RC_MISC);
130
131         if (status != ISC_R_SUCCESS)
132                 log_fatal ("Can't register pool object type: %s",
133                            isc_result_totext (status));
134
135         status = omapi_object_type_register (&dhcp_type_host,
136                                              "host",
137                                              dhcp_host_set_value,
138                                              dhcp_host_get_value,
139                                              dhcp_host_destroy,
140                                              dhcp_host_signal_handler,
141                                              dhcp_host_stuff_values,
142                                              dhcp_host_lookup, 
143                                              dhcp_host_create,
144                                              dhcp_host_remove, 0, 0, 0,
145                                              sizeof (struct host_decl),
146                                              0, RC_MISC);
147
148         if (status != ISC_R_SUCCESS)
149                 log_fatal ("Can't register host object type: %s",
150                            isc_result_totext (status));
151
152 #if defined (FAILOVER_PROTOCOL)
153         status = omapi_object_type_register (&dhcp_type_failover_state,
154                                              "failover-state",
155                                              dhcp_failover_state_set_value,
156                                              dhcp_failover_state_get_value,
157                                              dhcp_failover_state_destroy,
158                                              dhcp_failover_state_signal,
159                                              dhcp_failover_state_stuff,
160                                              dhcp_failover_state_lookup, 
161                                              dhcp_failover_state_create,
162                                              dhcp_failover_state_remove,
163                                              0, 0, 0,
164                                              sizeof (dhcp_failover_state_t),
165                                              0, RC_MISC);
166
167         if (status != ISC_R_SUCCESS)
168                 log_fatal ("Can't register failover state object type: %s",
169                            isc_result_totext (status));
170
171         status = omapi_object_type_register (&dhcp_type_failover_link,
172                                              "failover-link",
173                                              dhcp_failover_link_set_value,
174                                              dhcp_failover_link_get_value,
175                                              dhcp_failover_link_destroy,
176                                              dhcp_failover_link_signal,
177                                              dhcp_failover_link_stuff_values,
178                                              0, 0, 0, 0, 0, 0,
179                                              sizeof (dhcp_failover_link_t), 0,
180                                              RC_MISC);
181
182         if (status != ISC_R_SUCCESS)
183                 log_fatal ("Can't register failover link object type: %s",
184                            isc_result_totext (status));
185
186         status = omapi_object_type_register (&dhcp_type_failover_listener,
187                                              "failover-listener",
188                                              dhcp_failover_listener_set_value,
189                                              dhcp_failover_listener_get_value,
190                                              dhcp_failover_listener_destroy,
191                                              dhcp_failover_listener_signal,
192                                              dhcp_failover_listener_stuff,
193                                              0, 0, 0, 0, 0, 0,
194                                              sizeof
195                                              (dhcp_failover_listener_t), 0,
196                                              RC_MISC);
197
198         if (status != ISC_R_SUCCESS)
199                 log_fatal ("Can't register failover listener object type: %s",
200                            isc_result_totext (status));
201 #endif /* FAILOVER_PROTOCOL */
202 }
203
204 isc_result_t dhcp_lease_set_value  (omapi_object_t *h,
205                                     omapi_object_t *id,
206                                     omapi_data_string_t *name,
207                                     omapi_typed_data_t *value)
208 {
209         struct lease *lease;
210         isc_result_t status;
211         int foo;
212
213         if (h -> type != dhcp_type_lease)
214                 return ISC_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 ISC_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, 0, 1, 1, 1)) {
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 ISC_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 ISC_R_UNCHANGED;     /* XXX take change. */
251         } else if (!omapi_ds_strcmp (name, "hostname")) {
252             return ISC_R_UNCHANGED;     /* XXX take change. */
253         } else if (!omapi_ds_strcmp (name, "client-hostname")) {
254             return ISC_R_UNCHANGED;     /* XXX take change. */
255         } else if (!omapi_ds_strcmp (name, "host")) {
256             return ISC_R_UNCHANGED;     /* XXX take change. */
257         } else if (!omapi_ds_strcmp (name, "subnet")) {
258             return ISC_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             return ISC_R_NOPERM;
265         } else if (!omapi_ds_strcmp (name, "billing-class")) {
266             return ISC_R_UNCHANGED;     /* XXX carefully allow change. */
267         } else if (!omapi_ds_strcmp (name, "hardware-address")) {
268             return ISC_R_UNCHANGED;     /* XXX take change. */
269         } else if (!omapi_ds_strcmp (name, "hardware-type")) {
270             return ISC_R_UNCHANGED;     /* XXX take change. */
271         } else if (lease -> scope) {
272             status = binding_scope_set_value (lease -> scope, 0, name, value);
273             if (status == ISC_R_SUCCESS) {
274                     if (write_lease (lease) && commit_leases ())
275                             return ISC_R_SUCCESS;
276                     return ISC_R_IOERROR;
277             }
278         }
279
280         /* Try to find some inner object that can take the value. */
281         if (h -> inner && h -> inner -> type -> set_value) {
282                 status = ((*(h -> inner -> type -> set_value))
283                           (h -> inner, id, name, value));
284                 if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED)
285                         return status;
286         }
287                           
288         if (!lease -> scope) {
289                 if (!binding_scope_allocate (&lease -> scope, MDL))
290                         return ISC_R_NOMEMORY;
291         }
292         status = binding_scope_set_value (lease -> scope, 1, name, value);
293         if (status != ISC_R_SUCCESS)
294                 return status;
295
296         if (write_lease (lease) && commit_leases ())
297                 return ISC_R_SUCCESS;
298         return ISC_R_IOERROR;
299 }
300
301
302 isc_result_t dhcp_lease_get_value (omapi_object_t *h, omapi_object_t *id,
303                                    omapi_data_string_t *name,
304                                    omapi_value_t **value)
305 {
306         struct lease *lease;
307         isc_result_t status;
308
309         if (h -> type != dhcp_type_lease)
310                 return ISC_R_INVALIDARG;
311         lease = (struct lease *)h;
312
313         if (!omapi_ds_strcmp (name, "state"))
314                 return omapi_make_int_value (value, name,
315                                              (int)lease -> binding_state, MDL);
316         else if (!omapi_ds_strcmp (name, "ip-address"))
317                 return omapi_make_const_value (value, name,
318                                                lease -> ip_addr.iabuf,
319                                                lease -> ip_addr.len, MDL);
320         else if (!omapi_ds_strcmp (name, "dhcp-client-identifier")) {
321                 return omapi_make_const_value (value, name,
322                                                lease -> uid,
323                                                lease -> uid_len, MDL);
324         } else if (!omapi_ds_strcmp (name, "client-hostname")) {
325                 if (lease -> client_hostname)
326                         return omapi_make_string_value
327                                 (value, name, lease -> client_hostname, MDL);
328                 return ISC_R_NOTFOUND;
329         } else if (!omapi_ds_strcmp (name, "host")) {
330                 if (lease -> host)
331                         return omapi_make_handle_value
332                                 (value, name,
333                                  ((omapi_object_t *)lease -> host), MDL);
334         } else if (!omapi_ds_strcmp (name, "subnet"))
335                 return omapi_make_handle_value (value, name,
336                                                 ((omapi_object_t *)
337                                                  lease -> subnet), MDL);
338         else if (!omapi_ds_strcmp (name, "pool"))
339                 return omapi_make_handle_value (value, name,
340                                                 ((omapi_object_t *)
341                                                  lease -> pool), MDL);
342         else if (!omapi_ds_strcmp (name, "billing-class")) {
343                 if (lease -> billing_class)
344                         return omapi_make_handle_value
345                                 (value, name,
346                                  ((omapi_object_t *)lease -> billing_class),
347                                  MDL);
348                 return ISC_R_NOTFOUND;
349         } else if (!omapi_ds_strcmp (name, "hardware-address")) {
350                 if (lease -> hardware_addr.hlen)
351                         return omapi_make_const_value
352                                 (value, name, &lease -> hardware_addr.hbuf [1],
353                                  (unsigned)(lease -> hardware_addr.hlen - 1),
354                                  MDL);
355                 return ISC_R_NOTFOUND;
356         } else if (!omapi_ds_strcmp (name, "hardware-type")) {
357                 if (lease -> hardware_addr.hlen)
358                         return omapi_make_int_value
359                                 (value, name, lease -> hardware_addr.hbuf [0],
360                                  MDL);
361                 return ISC_R_NOTFOUND;
362         } else if (lease -> scope) {
363                 status = binding_scope_get_value (value, lease -> scope, name);
364                 if (status != ISC_R_NOTFOUND)
365                         return status;
366         }
367
368         /* Try to find some inner object that can take the value. */
369         if (h -> inner && h -> inner -> type -> get_value) {
370                 status = ((*(h -> inner -> type -> get_value))
371                           (h -> inner, id, name, value));
372                 if (status == ISC_R_SUCCESS)
373                         return status;
374         }
375         return ISC_R_UNKNOWNATTRIBUTE;
376 }
377
378 isc_result_t dhcp_lease_destroy (omapi_object_t *h, const char *file, int line)
379 {
380         struct lease *lease;
381         isc_result_t status;
382
383         if (h -> type != dhcp_type_lease)
384                 return ISC_R_INVALIDARG;
385         lease = (struct lease *)h;
386
387         if (lease -> uid)
388                 uid_hash_delete (lease);
389         hw_hash_delete (lease);
390
391         if (lease -> on_release)
392                 executable_statement_dereference (&lease -> on_release,
393                                                   file, line);
394         if (lease -> on_expiry)
395                 executable_statement_dereference (&lease -> on_expiry,
396                                                   file, line);
397         if (lease -> on_commit)
398                 executable_statement_dereference (&lease -> on_commit,
399                                                   file, line);
400         if (lease -> scope)
401                 binding_scope_dereference (&lease -> scope, file, line);
402
403         if (lease -> agent_options)
404                 option_chain_head_dereference (&lease -> agent_options,
405                                                file, line);
406         if (lease -> uid && lease -> uid != lease -> uid_buf) {
407                 dfree (lease -> uid, MDL);
408                 lease -> uid = &lease -> uid_buf [0];
409                 lease -> uid_len = 0;
410         }
411
412         if (lease -> client_hostname) {
413                 dfree (lease -> client_hostname, MDL);
414                 lease -> client_hostname = (char *)0;
415         }
416
417         if (lease -> host)
418                 host_dereference (&lease -> host, file, line);
419         if (lease -> subnet)
420                 subnet_dereference (&lease -> subnet, file, line);
421         if (lease -> pool)
422                 pool_dereference (&lease -> pool, file, line);
423
424         if (lease -> state) {
425                 free_lease_state (lease -> state, file, line);
426                 lease -> state = (struct lease_state *)0;
427
428                 cancel_timeout (lease_ping_timeout, lease);
429                 --outstanding_pings; /* XXX */
430         }
431
432         if (lease -> billing_class)
433                 class_dereference
434                         (&lease -> billing_class, file, line);
435
436 #if defined (DEBUG_MEMORY_LEAKAGE) || \
437                 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
438         /* XXX we should never be destroying a lease with a next
439            XXX pointer except on exit... */
440         if (lease -> next)
441                 lease_dereference (&lease -> next, file, line);
442         if (lease -> n_hw)
443                 lease_dereference (&lease -> n_hw, file, line);
444         if (lease -> n_uid)
445                 lease_dereference (&lease -> n_uid, file, line);
446         if (lease -> next_pending)
447                 lease_dereference (&lease -> next_pending, file, line);
448 #endif
449
450         return ISC_R_SUCCESS;
451 }
452
453 isc_result_t dhcp_lease_signal_handler (omapi_object_t *h,
454                                         const char *name, va_list ap)
455 {
456         struct lease *lease;
457         isc_result_t status;
458         int updatep = 0;
459
460         if (h -> type != dhcp_type_lease)
461                 return ISC_R_INVALIDARG;
462         lease = (struct lease *)h;
463
464         if (!strcmp (name, "updated"))
465                 return ISC_R_SUCCESS;
466
467         /* Try to find some inner object that can take the value. */
468         if (h -> inner && h -> inner -> type -> signal_handler) {
469                 status = ((*(h -> inner -> type -> signal_handler))
470                           (h -> inner, name, ap));
471                 if (status == ISC_R_SUCCESS)
472                         return status;
473         }
474         return ISC_R_NOTFOUND;
475 }
476
477 isc_result_t dhcp_lease_stuff_values (omapi_object_t *c,
478                                       omapi_object_t *id,
479                                       omapi_object_t *h)
480 {
481         struct lease *lease;
482         isc_result_t status;
483
484         if (h -> type != dhcp_type_lease)
485                 return ISC_R_INVALIDARG;
486         lease = (struct lease *)h;
487
488         /* Write out all the values. */
489
490         status = omapi_connection_put_name (c, "state");
491         if (status != ISC_R_SUCCESS)
492                 return status;
493         status = omapi_connection_put_uint32 (c, sizeof (int));
494         if (status != ISC_R_SUCCESS)
495                 return status;
496         status = omapi_connection_put_uint32 (c, lease -> binding_state);
497         if (status != ISC_R_SUCCESS)
498                 return status;
499
500         status = omapi_connection_put_name (c, "ip-address");
501         if (status != ISC_R_SUCCESS)
502                 return status;
503         status = omapi_connection_put_uint32 (c, lease -> ip_addr.len);
504         if (status != ISC_R_SUCCESS)
505                 return status;
506         status = omapi_connection_copyin (c, lease -> ip_addr.iabuf,
507                                           lease -> ip_addr.len);
508         if (status != ISC_R_SUCCESS)
509                 return status;
510
511         if (lease -> uid_len) {
512                 status = omapi_connection_put_name (c,
513                                                     "dhcp-client-identifier");
514                 if (status != ISC_R_SUCCESS)
515                         return status;
516                 status = omapi_connection_put_uint32 (c, lease -> uid_len);
517                 if (status != ISC_R_SUCCESS)
518                         return status;
519                 if (lease -> uid_len) {
520                         status = omapi_connection_copyin (c, lease -> uid,
521                                                           lease -> uid_len);
522                         if (status != ISC_R_SUCCESS)
523                                 return status;
524                 }
525         }
526
527         if (lease -> client_hostname) {
528                 status = omapi_connection_put_name (c, "client-hostname");
529                 if (status != ISC_R_SUCCESS)
530                         return status;
531                 status =
532                         omapi_connection_put_string (c,
533                                                      lease -> client_hostname);
534                 if (status != ISC_R_SUCCESS)
535                         return status;
536         }
537
538         if (lease -> host) {
539                 status = omapi_connection_put_name (c, "host");
540                 if (status != ISC_R_SUCCESS)
541                         return status;
542                 status = omapi_connection_put_handle (c,
543                                                       (omapi_object_t *)
544                                                       lease -> host);
545                 if (status != ISC_R_SUCCESS)
546                         return status;
547         }
548
549         status = omapi_connection_put_name (c, "subnet");
550         if (status != ISC_R_SUCCESS)
551                 return status;
552         status = omapi_connection_put_handle
553                 (c, (omapi_object_t *)lease -> subnet);
554         if (status != ISC_R_SUCCESS)
555                 return status;
556
557         status = omapi_connection_put_name (c, "pool");
558         if (status != ISC_R_SUCCESS)
559                 return status;
560         status = omapi_connection_put_handle (c,
561                                               (omapi_object_t *)lease -> pool);
562         if (status != ISC_R_SUCCESS)
563                 return status;
564
565         if (lease -> billing_class) {
566                 status = omapi_connection_put_name (c, "billing-class");
567                 if (status != ISC_R_SUCCESS)
568                         return status;
569                 status = omapi_connection_put_handle
570                         (c, (omapi_object_t *)lease -> billing_class);
571                 if (status != ISC_R_SUCCESS)
572                         return status;
573         }
574
575         if (lease -> hardware_addr.hlen) {
576                 status = omapi_connection_put_name (c, "hardware-address");
577                 if (status != ISC_R_SUCCESS)
578                         return status;
579                 status = (omapi_connection_put_uint32
580                           (c,
581                            (unsigned long)(lease -> hardware_addr.hlen - 1)));
582                 if (status != ISC_R_SUCCESS)
583                         return status;
584                 status = (omapi_connection_copyin
585                           (c, &lease -> hardware_addr.hbuf [1],
586                            (unsigned long)(lease -> hardware_addr.hlen - 1)));
587
588                 if (status != ISC_R_SUCCESS)
589                         return status;
590
591                 status = omapi_connection_put_name (c, "hardware-type");
592                 if (status != ISC_R_SUCCESS)
593                         return status;
594                 status = omapi_connection_put_uint32 (c, sizeof (int));
595                 if (status != ISC_R_SUCCESS)
596                         return status;
597                 status = omapi_connection_put_uint32
598                         (c, lease -> hardware_addr.hbuf [0]);
599                 if (status != ISC_R_SUCCESS)
600                         return status;
601         }
602
603
604         status = omapi_connection_put_name (c, "ends");
605         if (status != ISC_R_SUCCESS)
606                 return status;
607         status = omapi_connection_put_uint32 (c, sizeof (TIME));
608         if (status != ISC_R_SUCCESS)
609                 return status;
610         status = (omapi_connection_copyin
611                   (c, (const unsigned char *)&(lease -> ends), sizeof(TIME)));
612         if (status != ISC_R_SUCCESS)
613                 return status;
614
615         status = omapi_connection_put_name (c, "starts");
616         if (status != ISC_R_SUCCESS)
617                 return status;
618         status = omapi_connection_put_uint32 (c, sizeof (TIME));
619         if (status != ISC_R_SUCCESS)
620                 return status;
621         status = (omapi_connection_copyin
622                   (c,
623                    (const unsigned char *)&(lease -> starts), sizeof (TIME)));
624         if (status != ISC_R_SUCCESS)
625                 return status;
626
627         status = omapi_connection_put_name (c, "tstp");
628         if (status != ISC_R_SUCCESS)
629                 return status;
630         status = omapi_connection_put_uint32 (c, sizeof (TIME));
631         if (status != ISC_R_SUCCESS)
632                 return status;
633         status = (omapi_connection_copyin
634                   (c,
635                    (const unsigned char *)&(lease -> tstp), sizeof (TIME)));
636         if (status != ISC_R_SUCCESS)
637                 return status;
638
639         status = omapi_connection_put_name (c, "tsfp");
640         if (status != ISC_R_SUCCESS)
641                 return status;
642         status = omapi_connection_put_uint32 (c, sizeof (TIME));
643         if (status != ISC_R_SUCCESS)
644                 return status;
645         status = (omapi_connection_copyin
646                   (c,
647                    (const unsigned char *)&(lease -> tsfp), sizeof (TIME)));
648         if (status != ISC_R_SUCCESS)
649                 return status;
650
651         status = omapi_connection_put_name (c, "cltt");
652         if (status != ISC_R_SUCCESS)
653                 return status;
654         status = omapi_connection_put_uint32 (c, sizeof (TIME));
655         if (status != ISC_R_SUCCESS)
656                 return status;
657         status = (omapi_connection_copyin
658                   (c,
659                    (const unsigned char *)&(lease -> cltt), sizeof (TIME)));
660         if (status != ISC_R_SUCCESS)
661                 return status;
662
663         if (lease -> scope) {
664                 status = binding_scope_stuff_values (c, lease -> scope);
665                 if (status != ISC_R_SUCCESS)
666                         return status;
667         }
668
669         /* Write out the inner object, if any. */
670         if (h -> inner && h -> inner -> type -> stuff_values) {
671                 status = ((*(h -> inner -> type -> stuff_values))
672                           (c, id, h -> inner));
673                 if (status == ISC_R_SUCCESS)
674                         return status;
675         }
676
677         return ISC_R_SUCCESS;
678 }
679
680 isc_result_t dhcp_lease_lookup (omapi_object_t **lp,
681                                 omapi_object_t *id, omapi_object_t *ref)
682 {
683         omapi_value_t *tv = (omapi_value_t *)0;
684         isc_result_t status;
685         struct lease *lease;
686
687         if (!ref)
688                 return ISC_R_NOKEYS;
689
690         /* First see if we were sent a handle. */
691         status = omapi_get_value_str (ref, id, "handle", &tv);
692         if (status == ISC_R_SUCCESS) {
693                 status = omapi_handle_td_lookup (lp, tv -> value);
694
695                 omapi_value_dereference (&tv, MDL);
696                 if (status != ISC_R_SUCCESS)
697                         return status;
698
699                 /* Don't return the object if the type is wrong. */
700                 if ((*lp) -> type != dhcp_type_lease) {
701                         omapi_object_dereference (lp, MDL);
702                         return ISC_R_INVALIDARG;
703                 }
704         }
705
706         /* Now look for an IP address. */
707         status = omapi_get_value_str (ref, id, "ip-address", &tv);
708         if (status == ISC_R_SUCCESS) {
709                 lease = (struct lease *)0;
710                 lease_hash_lookup (&lease, lease_ip_addr_hash,
711                                    tv -> value -> u.buffer.value,
712                                    tv -> value -> u.buffer.len, MDL);
713
714                 omapi_value_dereference (&tv, MDL);
715
716                 /* If we already have a lease, and it's not the same one,
717                    then the query was invalid. */
718                 if (*lp && *lp != (omapi_object_t *)lease) {
719                         omapi_object_dereference (lp, MDL);
720                         lease_dereference (&lease, MDL);
721                         return ISC_R_KEYCONFLICT;
722                 } else if (!lease) {
723                         if (*lp)
724                                 omapi_object_dereference (lp, MDL);
725                         return ISC_R_NOTFOUND;
726                 } else if (!*lp) {
727                         /* XXX fix so that hash lookup itself creates
728                            XXX the reference. */
729                         omapi_object_reference (lp,
730                                                 (omapi_object_t *)lease, MDL);
731                         lease_dereference (&lease, MDL);
732                 }
733         }
734
735         /* Now look for a client identifier. */
736         status = omapi_get_value_str (ref, id, "dhcp-client-identifier", &tv);
737         if (status == ISC_R_SUCCESS) {
738                 lease = (struct lease *)0;
739                 lease_hash_lookup (&lease, lease_uid_hash,
740                                    tv -> value -> u.buffer.value,
741                                    tv -> value -> u.buffer.len, MDL);
742                 omapi_value_dereference (&tv, MDL);
743                         
744                 if (*lp && *lp != (omapi_object_t *)lease) {
745                         omapi_object_dereference (lp, MDL);
746                         lease_dereference (&lease, MDL);
747                         return ISC_R_KEYCONFLICT;
748                 } else if (!lease) {
749                         if (*lp)
750                             omapi_object_dereference (lp, MDL);
751                         return ISC_R_NOTFOUND;
752                 } else if (lease -> n_uid) {
753                         if (*lp)
754                             omapi_object_dereference (lp, MDL);
755                         return ISC_R_MULTIPLE;
756                 } else if (!*lp) {
757                         /* XXX fix so that hash lookup itself creates
758                            XXX the reference. */
759                         omapi_object_reference (lp,
760                                                 (omapi_object_t *)lease, MDL);
761                         lease_dereference (&lease, MDL);
762                 }
763         }
764
765         /* Now look for a hardware address. */
766         status = omapi_get_value_str (ref, id, "hardware-address", &tv);
767         if (status == ISC_R_SUCCESS) {
768                 unsigned char *haddr;
769                 unsigned int len;
770
771                 len = tv -> value -> u.buffer.len + 1;
772                 haddr = dmalloc (len, MDL);
773                 if (!haddr) {
774                         omapi_value_dereference (&tv, MDL);
775                         return ISC_R_NOMEMORY;
776                 }
777
778                 memcpy (haddr + 1, tv -> value -> u.buffer.value, len - 1);
779                 omapi_value_dereference (&tv, MDL);
780
781                 status = omapi_get_value_str (ref, id, "hardware-type", &tv);
782                 if (status == ISC_R_SUCCESS) {
783                         if (tv -> value -> type == omapi_datatype_data) {
784                                 if ((tv -> value -> u.buffer.len != 4) ||
785                                     (tv -> value -> u.buffer.value[0] != 0) ||
786                                     (tv -> value -> u.buffer.value[1] != 0) ||
787                                     (tv -> value -> u.buffer.value[2] != 0)) {
788                                         omapi_value_dereference (&tv, MDL);
789                                         dfree (haddr, MDL);
790                                         return ISC_R_INVALIDARG;
791                                 }
792
793                                 haddr[0] = tv -> value -> u.buffer.value[3];
794                         } else if (tv -> value -> type == omapi_datatype_int) {
795                                 haddr[0] = (unsigned char)
796                                         tv -> value -> u.integer;
797                         } else {
798                                 omapi_value_dereference (&tv, MDL);
799                                 dfree (haddr, MDL);
800                                 return ISC_R_INVALIDARG;
801                         }
802
803                         omapi_value_dereference (&tv, MDL);
804                 } else {
805                         /* If no hardware-type is specified, default to
806                            ethernet.  This may or may not be a good idea,
807                            but Telus is currently relying on this behavior.
808                            - DPN */
809                         haddr[0] = HTYPE_ETHER;
810                 }
811
812                 lease = (struct lease *)0;
813                 lease_hash_lookup (&lease, lease_hw_addr_hash, haddr, len, MDL);
814                 dfree (haddr, MDL);
815
816                 if (*lp && *lp != (omapi_object_t *)lease) {
817                         omapi_object_dereference (lp, MDL);
818                         lease_dereference (&lease, MDL);
819                         return ISC_R_KEYCONFLICT;
820                 } else if (!lease) {
821                         if (*lp)
822                             omapi_object_dereference (lp, MDL);
823                         return ISC_R_NOTFOUND;
824                 } else if (lease -> n_hw) {
825                         if (*lp)
826                             omapi_object_dereference (lp, MDL);
827                         lease_dereference (&lease, MDL);
828                         return ISC_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         /* If we get to here without finding a lease, no valid key was
839            specified. */
840         if (!*lp)
841                 return ISC_R_NOKEYS;
842         return ISC_R_SUCCESS;
843 }
844
845 isc_result_t dhcp_lease_create (omapi_object_t **lp,
846                                 omapi_object_t *id)
847 {
848         return ISC_R_NOTIMPLEMENTED;
849 }
850
851 isc_result_t dhcp_lease_remove (omapi_object_t *lp,
852                                 omapi_object_t *id)
853 {
854         return ISC_R_NOTIMPLEMENTED;
855 }
856
857 isc_result_t dhcp_host_set_value  (omapi_object_t *h,
858                                    omapi_object_t *id,
859                                    omapi_data_string_t *name,
860                                    omapi_typed_data_t *value)
861 {
862         struct host_decl *host, *hp;
863         isc_result_t status;
864         int foo;
865
866         if (h -> type != dhcp_type_host)
867                 return ISC_R_INVALIDARG;
868         host = (struct host_decl *)h;
869
870         /* XXX For now, we can only set these values on new host objects. 
871            XXX Soon, we need to be able to update host objects. */
872         if (!omapi_ds_strcmp (name, "name")) {
873                 if (host -> name)
874                         return ISC_R_EXISTS;
875                 if (value && (value -> type == omapi_datatype_data ||
876                               value -> type == omapi_datatype_string)) {
877                         host -> name = dmalloc (value -> u.buffer.len + 1,
878                                                 MDL);
879                         if (!host -> name)
880                                 return ISC_R_NOMEMORY;
881                         memcpy (host -> name,
882                                 value -> u.buffer.value,
883                                 value -> u.buffer.len);
884                         host -> name [value -> u.buffer.len] = 0;
885                 } else
886                         return ISC_R_INVALIDARG;
887                 return ISC_R_SUCCESS;
888         }
889
890         if (!omapi_ds_strcmp (name, "group")) {
891                 if (value && (value -> type == omapi_datatype_data ||
892                               value -> type == omapi_datatype_string)) {
893                         struct group_object *group;
894                         group = (struct group_object *)0;
895                         group_hash_lookup (&group, group_name_hash,
896                                            (char *)value -> u.buffer.value,
897                                            value -> u.buffer.len, MDL);
898                         if (!group || (group -> flags & GROUP_OBJECT_DELETED))
899                                 return ISC_R_NOTFOUND;
900                         if (host -> group)
901                                 group_dereference (&host -> group, MDL);
902                         group_reference (&host -> group, group -> group, MDL);
903                         if (host -> named_group)
904                                 group_object_dereference (&host -> named_group,
905                                                           MDL);
906                         group_object_reference (&host -> named_group,
907                                                 group, MDL);
908                         group_object_dereference (&group, MDL);
909                 } else
910                         return ISC_R_INVALIDARG;
911                 return ISC_R_SUCCESS;
912         }
913
914         if (!omapi_ds_strcmp (name, "hardware-address")) {
915                 if (host -> interface.hlen)
916                         return ISC_R_EXISTS;
917                 if (value && (value -> type == omapi_datatype_data ||
918                               value -> type == omapi_datatype_string)) {
919                         if (value -> u.buffer.len >
920                             (sizeof host -> interface.hbuf) - 1)
921                                 return ISC_R_INVALIDARG;
922                         memcpy (&host -> interface.hbuf [1],
923                                 value -> u.buffer.value,
924                                 value -> u.buffer.len);
925                         host -> interface.hlen = value -> u.buffer.len + 1;
926                 } else
927                         return ISC_R_INVALIDARG;
928                 return ISC_R_SUCCESS;
929         }
930
931         if (!omapi_ds_strcmp (name, "hardware-type")) {
932                 int type;
933                 if (value && (value -> type == omapi_datatype_data &&
934                               value -> u.buffer.len == sizeof type)) {
935                         if (value -> u.buffer.len > sizeof type)
936                                 return ISC_R_INVALIDARG;
937                         memcpy (&type,
938                                 value -> u.buffer.value,
939                                 value -> u.buffer.len);
940                         type = ntohl (type);
941                 } else if (value -> type == omapi_datatype_int)
942                         type = value -> u.integer;
943                 else
944                         return ISC_R_INVALIDARG;
945                 host -> interface.hbuf [0] = type;
946                 return ISC_R_SUCCESS;
947         }
948
949         if (!omapi_ds_strcmp (name, "dhcp-client-identifier")) {
950                 if (host -> client_identifier.data)
951                         return ISC_R_EXISTS;
952                 if (value && (value -> type == omapi_datatype_data ||
953                               value -> type == omapi_datatype_string)) {
954                     if (!buffer_allocate (&host -> client_identifier.buffer,
955                                           value -> u.buffer.len, MDL))
956                             return ISC_R_NOMEMORY;
957                     host -> client_identifier.data =
958                             &host -> client_identifier.buffer -> data [0];
959                     memcpy (host -> client_identifier.buffer -> data,
960                             value -> u.buffer.value,
961                             value -> u.buffer.len);
962                     host -> client_identifier.len = value -> u.buffer.len;
963                 } else
964                     return ISC_R_INVALIDARG;
965                 return ISC_R_SUCCESS;
966         }
967
968         if (!omapi_ds_strcmp (name, "ip-address")) {
969                 if (host -> fixed_addr)
970                         option_cache_dereference (&host -> fixed_addr, MDL);
971                 if (!value)
972                         return ISC_R_SUCCESS;
973                 if (value && (value -> type == omapi_datatype_data ||
974                               value -> type == omapi_datatype_string)) {
975                         struct data_string ds;
976                         memset (&ds, 0, sizeof ds);
977                         ds.len = value -> u.buffer.len;
978                         if (!buffer_allocate (&ds.buffer, ds.len, MDL))
979                                 return ISC_R_NOMEMORY;
980                         ds.data = (&ds.buffer -> data [0]);
981                         memcpy (ds.buffer -> data,
982                                 value -> u.buffer.value, ds.len);
983                         if (!option_cache (&host -> fixed_addr,
984                                            &ds, (struct expression *)0,
985                                            (struct option *)0, MDL)) {
986                                 data_string_forget (&ds, MDL);
987                                 return ISC_R_NOMEMORY;
988                         }
989                         data_string_forget (&ds, MDL);
990                 } else
991                         return ISC_R_INVALIDARG;
992                 return ISC_R_SUCCESS;
993         }
994
995         if (!omapi_ds_strcmp (name, "statements")) {
996                 if (!host -> group) {
997                         if (!clone_group (&host -> group, root_group, MDL))
998                                 return ISC_R_NOMEMORY;
999                 } else {
1000                         if (host -> group -> statements &&
1001                             (!host -> named_group ||
1002                              host -> group != host -> named_group -> group) &&
1003                             host -> group != root_group)
1004                                 return ISC_R_EXISTS;
1005                         if (!clone_group (&host -> group, host -> group, MDL))
1006                                 return ISC_R_NOMEMORY;
1007                 }
1008                 if (!host -> group)
1009                         return ISC_R_NOMEMORY;
1010                 if (value && (value -> type == omapi_datatype_data ||
1011                               value -> type == omapi_datatype_string)) {
1012                         struct parse *parse;
1013                         int lose = 0;
1014                         parse = (struct parse *)0;
1015                         status = new_parse (&parse, -1,
1016                                             (char *)value -> u.buffer.value,
1017                                             value -> u.buffer.len,
1018                                             "network client", 0);
1019                         if (status != ISC_R_SUCCESS)
1020                                 return status;
1021                         if (!(parse_executable_statements
1022                               (&host -> group -> statements, parse, &lose,
1023                                context_any))) {
1024                                 end_parse (&parse);
1025                                 return ISC_R_BADPARSE;
1026                         }
1027                         end_parse (&parse);
1028                 } else
1029                         return ISC_R_INVALIDARG;
1030                 return ISC_R_SUCCESS;
1031         }
1032
1033         /* The "known" flag isn't supported in the database yet, but it's
1034            legitimate. */
1035         if (!omapi_ds_strcmp (name, "known")) {
1036                 return ISC_R_SUCCESS;
1037         }
1038
1039         /* Try to find some inner object that can take the value. */
1040         if (h -> inner && h -> inner -> type -> set_value) {
1041                 status = ((*(h -> inner -> type -> set_value))
1042                           (h -> inner, id, name, value));
1043                 if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED)
1044                         return status;
1045         }
1046                           
1047         return ISC_R_UNKNOWNATTRIBUTE;
1048 }
1049
1050
1051 isc_result_t dhcp_host_get_value (omapi_object_t *h, omapi_object_t *id,
1052                                    omapi_data_string_t *name,
1053                                    omapi_value_t **value)
1054 {
1055         struct host_decl *host;
1056         isc_result_t status;
1057         struct data_string ip_addrs;
1058
1059         if (h -> type != dhcp_type_host)
1060                 return ISC_R_INVALIDARG;
1061         host = (struct host_decl *)h;
1062
1063         if (!omapi_ds_strcmp (name, "ip-addresses")) {
1064             memset (&ip_addrs, 0, sizeof ip_addrs);
1065             if (host -> fixed_addr &&
1066                 evaluate_option_cache (&ip_addrs, (struct packet *)0,
1067                                        (struct lease *)0,
1068                                        (struct client_state *)0,
1069                                        (struct option_state *)0,
1070                                        (struct option_state *)0,
1071                                        &global_scope,
1072                                        host -> fixed_addr, MDL)) {
1073                     status = omapi_make_const_value (value, name,
1074                                                      ip_addrs.data,
1075                                                      ip_addrs.len, MDL);
1076                     data_string_forget (&ip_addrs, MDL);
1077                     return status;
1078             }
1079             return ISC_R_NOTFOUND;
1080         }
1081
1082         if (!omapi_ds_strcmp (name, "dhcp-client-identifier")) {
1083                 if (!host -> client_identifier.len)
1084                         return ISC_R_NOTFOUND;
1085                 return omapi_make_const_value (value, name,
1086                                                host -> client_identifier.data,
1087                                                host -> client_identifier.len,
1088                                                MDL);
1089         }
1090
1091         if (!omapi_ds_strcmp (name, "name"))
1092                 return omapi_make_string_value (value, name, host -> name,
1093                                                 MDL);
1094
1095         if (!omapi_ds_strcmp (name, "hardware-address")) {
1096                 if (!host -> interface.hlen)
1097                         return ISC_R_NOTFOUND;
1098                 return (omapi_make_const_value
1099                         (value, name, &host -> interface.hbuf [1],
1100                          (unsigned long)(host -> interface.hlen - 1), MDL));
1101         }
1102
1103         if (!omapi_ds_strcmp (name, "hardware-type")) {
1104                 if (!host -> interface.hlen)
1105                         return ISC_R_NOTFOUND;
1106                 return omapi_make_int_value (value, name,
1107                                              host -> interface.hbuf [0], MDL);
1108         }
1109
1110         /* Try to find some inner object that can take the value. */
1111         if (h -> inner && h -> inner -> type -> get_value) {
1112                 status = ((*(h -> inner -> type -> get_value))
1113                           (h -> inner, id, name, value));
1114                 if (status == ISC_R_SUCCESS)
1115                         return status;
1116         }
1117         return ISC_R_UNKNOWNATTRIBUTE;
1118 }
1119
1120 isc_result_t dhcp_host_destroy (omapi_object_t *h, const char *file, int line)
1121 {
1122         struct host_decl *host;
1123         isc_result_t status;
1124
1125         if (h -> type != dhcp_type_host)
1126                 return ISC_R_INVALIDARG;
1127         host = (struct host_decl *)h;
1128
1129 #if defined (DEBUG_MEMORY_LEAKAGE) || \
1130                 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1131         if (host -> n_ipaddr)
1132                 host_dereference (&host -> n_ipaddr, file, line);
1133         if (host -> n_dynamic)
1134                 host_dereference (&host -> n_dynamic, file, line);
1135         if (host -> name) {
1136                 dfree (host -> name, file, line);
1137                 host -> name = (char *)0;
1138         }
1139         data_string_forget (&host -> client_identifier, file, line);
1140         if (host -> fixed_addr)
1141                 option_cache_dereference (&host -> fixed_addr, file, line);
1142         if (host -> group)
1143                 group_dereference (&host -> group, file, line);
1144         if (host -> named_group)
1145                 omapi_object_dereference ((omapi_object_t **)
1146                                           &host -> named_group, file, line);
1147         data_string_forget (&host -> auth_key_id, file, line);
1148 #endif
1149
1150         return ISC_R_SUCCESS;
1151 }
1152
1153 isc_result_t dhcp_host_signal_handler (omapi_object_t *h,
1154                                        const char *name, va_list ap)
1155 {
1156         struct host_decl *host;
1157         isc_result_t status;
1158         int updatep = 0;
1159
1160         if (h -> type != dhcp_type_host)
1161                 return ISC_R_INVALIDARG;
1162         host = (struct host_decl *)h;
1163
1164         if (!strcmp (name, "updated")) {
1165                 /* There must be a client identifier of some sort. */
1166                 if (host -> interface.hlen == 0 &&
1167                     !host -> client_identifier.len)
1168                         return ISC_R_INVALIDARG;
1169
1170                 if (!host -> name) {
1171                         char hnbuf [64];
1172                         sprintf (hnbuf, "nh%08lx%08lx",
1173                                  (unsigned long)cur_time, (unsigned long)host);
1174                         host -> name = dmalloc (strlen (hnbuf) + 1, MDL);
1175                         if (!host -> name)
1176                                 return ISC_R_NOMEMORY;
1177                         strcpy (host -> name, hnbuf);
1178                 }
1179
1180 #ifdef DEBUG_OMAPI
1181                 log_debug ("OMAPI added host %s", host -> name);
1182 #endif
1183                 status = enter_host (host, 1, 1);
1184                 if (status != ISC_R_SUCCESS)
1185                         return status;
1186                 updatep = 1;
1187         }
1188
1189         /* Try to find some inner object that can take the value. */
1190         if (h -> inner && h -> inner -> type -> signal_handler) {
1191                 status = ((*(h -> inner -> type -> signal_handler))
1192                           (h -> inner, name, ap));
1193                 if (status == ISC_R_SUCCESS)
1194                         return status;
1195         }
1196         if (updatep)
1197                 return ISC_R_SUCCESS;
1198         return ISC_R_NOTFOUND;
1199 }
1200
1201 isc_result_t dhcp_host_stuff_values (omapi_object_t *c,
1202                                       omapi_object_t *id,
1203                                       omapi_object_t *h)
1204 {
1205         struct host_decl *host;
1206         isc_result_t status;
1207         struct data_string ip_addrs;
1208
1209         if (h -> type != dhcp_type_host)
1210                 return ISC_R_INVALIDARG;
1211         host = (struct host_decl *)h;
1212
1213         /* Write out all the values. */
1214
1215         memset (&ip_addrs, 0, sizeof ip_addrs);
1216         if (host -> fixed_addr &&
1217             evaluate_option_cache (&ip_addrs, (struct packet *)0,
1218                                    (struct lease *)0,
1219                                    (struct client_state *)0,
1220                                    (struct option_state *)0,
1221                                    (struct option_state *)0,
1222                                    &global_scope,
1223                                    host -> fixed_addr, MDL)) {
1224                 status = omapi_connection_put_name (c, "ip-address");
1225                 if (status != ISC_R_SUCCESS)
1226                         return status;
1227                 status = omapi_connection_put_uint32 (c, ip_addrs.len);
1228                 if (status != ISC_R_SUCCESS)
1229                         return status;
1230                 status = omapi_connection_copyin (c,
1231                                                   ip_addrs.data, ip_addrs.len);
1232                 if (status != ISC_R_SUCCESS)
1233                         return status;
1234         }
1235
1236         if (host -> client_identifier.len) {
1237                 status = omapi_connection_put_name (c,
1238                                                     "dhcp-client-identifier");
1239                 if (status != ISC_R_SUCCESS)
1240                         return status;
1241                 status = (omapi_connection_put_uint32
1242                           (c, host -> client_identifier.len));
1243                 if (status != ISC_R_SUCCESS)
1244                         return status;
1245                 status = (omapi_connection_copyin
1246                           (c,
1247                            host -> client_identifier.data,
1248                            host -> client_identifier.len));
1249                 if (status != ISC_R_SUCCESS)
1250                         return status;
1251         }
1252
1253         if (host -> name) {
1254                 status = omapi_connection_put_name (c, "name");
1255                 if (status != ISC_R_SUCCESS)
1256                         return status;
1257                 status = omapi_connection_put_string (c, host -> name);
1258                 if (status != ISC_R_SUCCESS)
1259                         return status;
1260         }
1261
1262         if (host -> interface.hlen) {
1263                 status = omapi_connection_put_name (c, "hardware-address");
1264                 if (status != ISC_R_SUCCESS)
1265                         return status;
1266                 status = (omapi_connection_put_uint32
1267                           (c, (unsigned long)(host -> interface.hlen - 1)));
1268                 if (status != ISC_R_SUCCESS)
1269                         return status;
1270                 status = (omapi_connection_copyin
1271                           (c, &host -> interface.hbuf [1],
1272                            (unsigned long)(host -> interface.hlen - 1)));
1273                 if (status != ISC_R_SUCCESS)
1274                         return status;
1275
1276                 status = omapi_connection_put_name (c, "hardware-type");
1277                 if (status != ISC_R_SUCCESS)
1278                         return status;
1279                 status = omapi_connection_put_uint32 (c, sizeof (int));
1280                 if (status != ISC_R_SUCCESS)
1281                         return status;
1282                 status = (omapi_connection_put_uint32
1283                           (c, host -> interface.hbuf [0]));
1284                 if (status != ISC_R_SUCCESS)
1285                         return status;
1286         }
1287
1288         /* Write out the inner object, if any. */
1289         if (h -> inner && h -> inner -> type -> stuff_values) {
1290                 status = ((*(h -> inner -> type -> stuff_values))
1291                           (c, id, h -> inner));
1292                 if (status == ISC_R_SUCCESS)
1293                         return status;
1294         }
1295
1296         return ISC_R_SUCCESS;
1297 }
1298
1299 isc_result_t dhcp_host_lookup (omapi_object_t **lp,
1300                                 omapi_object_t *id, omapi_object_t *ref)
1301 {
1302         omapi_value_t *tv = (omapi_value_t *)0;
1303         isc_result_t status;
1304         struct host_decl *host;
1305
1306         if (!ref)
1307                 return ISC_R_NOKEYS;
1308
1309         /* First see if we were sent a handle. */
1310         status = omapi_get_value_str (ref, id, "handle", &tv);
1311         if (status == ISC_R_SUCCESS) {
1312                 status = omapi_handle_td_lookup (lp, tv -> value);
1313
1314                 omapi_value_dereference (&tv, MDL);
1315                 if (status != ISC_R_SUCCESS)
1316                         return status;
1317
1318                 /* Don't return the object if the type is wrong. */
1319                 if ((*lp) -> type != dhcp_type_host) {
1320                         omapi_object_dereference (lp, MDL);
1321                         return ISC_R_INVALIDARG;
1322                 }
1323                 if (((struct host_decl *)(*lp)) -> flags & HOST_DECL_DELETED) {
1324                         omapi_object_dereference (lp, MDL);
1325                 }
1326         }
1327
1328         /* Now look for a client identifier. */
1329         status = omapi_get_value_str (ref, id, "dhcp-client-identifier", &tv);
1330         if (status == ISC_R_SUCCESS) {
1331                 host = (struct host_decl *)0;
1332                 host_hash_lookup (&host, host_uid_hash,
1333                                   tv -> value -> u.buffer.value,
1334                                   tv -> value -> u.buffer.len, MDL);
1335                 omapi_value_dereference (&tv, MDL);
1336                         
1337                 if (*lp && *lp != (omapi_object_t *)host) {
1338                         omapi_object_dereference (lp, MDL);
1339                         if (host)
1340                                 host_dereference (&host, MDL);
1341                         return ISC_R_KEYCONFLICT;
1342                 } else if (!host || (host -> flags & HOST_DECL_DELETED)) {
1343                         if (*lp)
1344                             omapi_object_dereference (lp, MDL);
1345                         if (host)
1346                                 host_dereference (&host, MDL);
1347                         return ISC_R_NOTFOUND;
1348                 } else if (!*lp) {
1349                         /* XXX fix so that hash lookup itself creates
1350                            XXX the reference. */
1351                         omapi_object_reference (lp,
1352                                                 (omapi_object_t *)host, MDL);
1353                         host_dereference (&host, MDL);
1354                 }
1355         }
1356
1357         /* Now look for a hardware address. */
1358         status = omapi_get_value_str (ref, id, "hardware-address", &tv);
1359         if (status == ISC_R_SUCCESS) {
1360                 unsigned char *haddr;
1361                 unsigned int len;
1362
1363                 len = tv -> value -> u.buffer.len + 1;
1364                 haddr = dmalloc (len, MDL);
1365                 if (!haddr) {
1366                         omapi_value_dereference (&tv, MDL);
1367                         return ISC_R_NOMEMORY;
1368                 }
1369
1370                 memcpy (haddr + 1, tv -> value -> u.buffer.value, len - 1);
1371                 omapi_value_dereference (&tv, MDL);
1372
1373                 status = omapi_get_value_str (ref, id, "hardware-type", &tv);
1374                 if (status == ISC_R_SUCCESS) {
1375                         if (tv -> value -> type == omapi_datatype_data) {
1376                                 if ((tv -> value -> u.buffer.len != 4) ||
1377                                     (tv -> value -> u.buffer.value[0] != 0) ||
1378                                     (tv -> value -> u.buffer.value[1] != 0) ||
1379                                     (tv -> value -> u.buffer.value[2] != 0)) {
1380                                         omapi_value_dereference (&tv, MDL);
1381                                         dfree (haddr, MDL);
1382                                         return ISC_R_INVALIDARG;
1383                                 }
1384
1385                                 haddr[0] = tv -> value -> u.buffer.value[3];
1386                         } else if (tv -> value -> type == omapi_datatype_int) {
1387                                 haddr[0] = (unsigned char)
1388                                         tv -> value -> u.integer;
1389                         } else {
1390                                 omapi_value_dereference (&tv, MDL);
1391                                 dfree (haddr, MDL);
1392                                 return ISC_R_INVALIDARG;
1393                         }
1394
1395                         omapi_value_dereference (&tv, MDL);
1396                 } else {
1397                         /* If no hardware-type is specified, default to
1398                            ethernet.  This may or may not be a good idea,
1399                            but Telus is currently relying on this behavior.
1400                            - DPN */
1401                         haddr[0] = HTYPE_ETHER;
1402                 }
1403
1404                 host = (struct host_decl *)0;
1405                 host_hash_lookup (&host, host_hw_addr_hash, haddr, len, MDL);
1406                 dfree (haddr, MDL);
1407                         
1408                 if (*lp && *lp != (omapi_object_t *)host) {
1409                         omapi_object_dereference (lp, MDL);
1410                         if (host)
1411                                 host_dereference (&host, MDL);
1412                         return ISC_R_KEYCONFLICT;
1413                 } else if (!host || (host -> flags & HOST_DECL_DELETED)) {
1414                         if (*lp)
1415                             omapi_object_dereference (lp, MDL);
1416                         if (host)
1417                                 host_dereference (&host, MDL);
1418                         return ISC_R_NOTFOUND;
1419                 } else if (!*lp) {
1420                         /* XXX fix so that hash lookup itself creates
1421                            XXX the reference. */
1422                         omapi_object_reference (lp,
1423                                                 (omapi_object_t *)host, MDL);
1424                         host_dereference (&host, MDL);
1425                 }
1426         }
1427
1428         /* Now look for an ip address. */
1429         status = omapi_get_value_str (ref, id, "ip-address", &tv);
1430         if (status == ISC_R_SUCCESS) {
1431                 struct lease *l;
1432
1433                 /* first find the lease for this ip address */
1434                 l = (struct lease *)0;
1435                 lease_hash_lookup (&l, lease_ip_addr_hash,
1436                                    tv -> value -> u.buffer.value,
1437                                    tv -> value -> u.buffer.len, MDL);
1438                 omapi_value_dereference (&tv, MDL);
1439
1440                 if (!l && !*lp)
1441                         return ISC_R_NOTFOUND;
1442
1443                 if (l) {
1444                         /* now use that to get a host */
1445                         host = (struct host_decl *)0;
1446                         host_hash_lookup (&host, host_hw_addr_hash,
1447                                           l -> hardware_addr.hbuf,
1448                                           l -> hardware_addr.hlen, MDL);
1449                         
1450                         if (host && *lp && *lp != (omapi_object_t *)host) {
1451                             omapi_object_dereference (lp, MDL);
1452                             if (host)
1453                                 host_dereference (&host, MDL);
1454                             return ISC_R_KEYCONFLICT;
1455                         } else if (!host || (host -> flags &
1456                                              HOST_DECL_DELETED)) {
1457                             if (host)
1458                                 host_dereference (&host, MDL);
1459                             if (!*lp)
1460                                     return ISC_R_NOTFOUND;
1461                         } else if (!*lp) {
1462                                 /* XXX fix so that hash lookup itself creates
1463                                    XXX the reference. */
1464                             omapi_object_reference (lp, (omapi_object_t *)host,
1465                                                     MDL);
1466                             host_dereference (&host, MDL);
1467                         }
1468                         lease_dereference (&l, MDL);
1469                 }
1470         }
1471
1472         /* Now look for a name. */
1473         status = omapi_get_value_str (ref, id, "name", &tv);
1474         if (status == ISC_R_SUCCESS) {
1475                 host = (struct host_decl *)0;
1476                 host_hash_lookup (&host, host_name_hash,
1477                                   tv -> value -> u.buffer.value,
1478                                   tv -> value -> u.buffer.len, MDL);
1479                 omapi_value_dereference (&tv, MDL);
1480                         
1481                 if (*lp && *lp != (omapi_object_t *)host) {
1482                         omapi_object_dereference (lp, MDL);
1483                         if (host)
1484                             host_dereference (&host, MDL);
1485                         return ISC_R_KEYCONFLICT;
1486                 } else if (!host || (host -> flags & HOST_DECL_DELETED)) {
1487                         if (host)
1488                             host_dereference (&host, MDL);
1489                         return ISC_R_NOTFOUND;  
1490                 } else if (!*lp) {
1491                         /* XXX fix so that hash lookup itself creates
1492                            XXX the reference. */
1493                         omapi_object_reference (lp,
1494                                                 (omapi_object_t *)host, MDL);
1495                         host_dereference (&host, MDL);
1496                 }
1497         }
1498
1499         /* If we get to here without finding a host, no valid key was
1500            specified. */
1501         if (!*lp)
1502                 return ISC_R_NOKEYS;
1503         return ISC_R_SUCCESS;
1504 }
1505
1506 isc_result_t dhcp_host_create (omapi_object_t **lp,
1507                                omapi_object_t *id)
1508 {
1509         struct host_decl *hp;
1510         isc_result_t status;
1511         hp = (struct host_decl *)0;
1512         status = host_allocate (&hp, MDL);
1513         if (status != ISC_R_SUCCESS)
1514                 return status;
1515         group_reference (&hp -> group, root_group, MDL);
1516         hp -> flags = HOST_DECL_DYNAMIC;
1517         status = omapi_object_reference (lp, (omapi_object_t *)hp, MDL);
1518         host_dereference (&hp, MDL);
1519         return status;
1520 }
1521
1522 isc_result_t dhcp_host_remove (omapi_object_t *lp,
1523                                omapi_object_t *id)
1524 {
1525         struct host_decl *hp;
1526         if (lp -> type != dhcp_type_host)
1527                 return ISC_R_INVALIDARG;
1528         hp = (struct host_decl *)lp;
1529
1530 #ifdef DEBUG_OMAPI
1531         log_debug ("OMAPI delete host %s", hp -> name);
1532 #endif
1533         delete_host (hp, 1);
1534         return ISC_R_SUCCESS;
1535 }
1536
1537 isc_result_t dhcp_pool_set_value  (omapi_object_t *h,
1538                                    omapi_object_t *id,
1539                                    omapi_data_string_t *name,
1540                                    omapi_typed_data_t *value)
1541 {
1542         struct pool *pool;
1543         isc_result_t status;
1544         int foo;
1545
1546         if (h -> type != dhcp_type_pool)
1547                 return ISC_R_INVALIDARG;
1548         pool = (struct pool *)h;
1549
1550         /* No values to set yet. */
1551
1552         /* Try to find some inner object that can take the value. */
1553         if (h -> inner && h -> inner -> type -> set_value) {
1554                 status = ((*(h -> inner -> type -> set_value))
1555                           (h -> inner, id, name, value));
1556                 if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED)
1557                         return status;
1558         }
1559                           
1560         return ISC_R_UNKNOWNATTRIBUTE;
1561 }
1562
1563
1564 isc_result_t dhcp_pool_get_value (omapi_object_t *h, omapi_object_t *id,
1565                                   omapi_data_string_t *name,
1566                                   omapi_value_t **value)
1567 {
1568         struct pool *pool;
1569         isc_result_t status;
1570
1571         if (h -> type != dhcp_type_pool)
1572                 return ISC_R_INVALIDARG;
1573         pool = (struct pool *)h;
1574
1575         /* No values to get yet. */
1576
1577         /* Try to find some inner object that can provide the value. */
1578         if (h -> inner && h -> inner -> type -> get_value) {
1579                 status = ((*(h -> inner -> type -> get_value))
1580                           (h -> inner, id, name, value));
1581                 if (status == ISC_R_SUCCESS)
1582                         return status;
1583         }
1584         return ISC_R_UNKNOWNATTRIBUTE;
1585 }
1586
1587 isc_result_t dhcp_pool_destroy (omapi_object_t *h, const char *file, int line)
1588 {
1589         struct pool *pool;
1590         isc_result_t status;
1591         struct permit *pc, *pn;
1592
1593         if (h -> type != dhcp_type_pool)
1594                 return ISC_R_INVALIDARG;
1595         pool = (struct pool *)h;
1596
1597 #if defined (DEBUG_MEMORY_LEAKAGE) || \
1598                 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1599         if (pool -> next)
1600                 pool_dereference (&pool -> next, file, line);
1601         if (pool -> group)
1602                 group_dereference (&pool -> group, file, line);
1603         if (pool -> shared_network)
1604             shared_network_dereference (&pool -> shared_network, file, line);
1605         if (pool -> active)
1606                 lease_dereference (&pool -> active, file, line);
1607         if (pool -> expired)
1608                 lease_dereference (&pool -> expired, file, line);
1609         if (pool -> free)
1610                 lease_dereference (&pool -> free, file, line);
1611         if (pool -> backup)
1612                 lease_dereference (&pool -> backup, file, line);
1613         if (pool -> abandoned)
1614                 lease_dereference (&pool -> abandoned, file, line);
1615 #if defined (FAILOVER_PROTOCOL)
1616         if (pool -> failover_peer)
1617                 dhcp_failover_state_dereference (&pool -> failover_peer,
1618                                                  file, line);
1619 #endif
1620         for (pc = pool -> permit_list; pc; pc = pn) {
1621                 pn = pc -> next;
1622                 free_permit (pc, file, line);
1623         }
1624         pool -> permit_list = (struct permit *)0;
1625
1626         for (pc = pool -> prohibit_list; pc; pc = pn) {
1627                 pn = pc -> next;
1628                 free_permit (pc, file, line);
1629         }
1630         pool -> prohibit_list = (struct permit *)0;
1631 #endif
1632
1633         return ISC_R_SUCCESS;
1634 }
1635
1636 isc_result_t dhcp_pool_signal_handler (omapi_object_t *h,
1637                                        const char *name, va_list ap)
1638 {
1639         struct pool *pool;
1640         isc_result_t status;
1641         int updatep = 0;
1642
1643         if (h -> type != dhcp_type_pool)
1644                 return ISC_R_INVALIDARG;
1645         pool = (struct pool *)h;
1646
1647         /* Can't write pools yet. */
1648
1649         /* Try to find some inner object that can take the value. */
1650         if (h -> inner && h -> inner -> type -> signal_handler) {
1651                 status = ((*(h -> inner -> type -> signal_handler))
1652                           (h -> inner, name, ap));
1653                 if (status == ISC_R_SUCCESS)
1654                         return status;
1655         }
1656         if (updatep)
1657                 return ISC_R_SUCCESS;
1658         return ISC_R_NOTFOUND;
1659 }
1660
1661 isc_result_t dhcp_pool_stuff_values (omapi_object_t *c,
1662                                      omapi_object_t *id,
1663                                      omapi_object_t *h)
1664 {
1665         struct pool *pool;
1666         isc_result_t status;
1667
1668         if (h -> type != dhcp_type_pool)
1669                 return ISC_R_INVALIDARG;
1670         pool = (struct pool *)h;
1671
1672         /* Can't stuff pool values yet. */
1673
1674         /* Write out the inner object, if any. */
1675         if (h -> inner && h -> inner -> type -> stuff_values) {
1676                 status = ((*(h -> inner -> type -> stuff_values))
1677                           (c, id, h -> inner));
1678                 if (status == ISC_R_SUCCESS)
1679                         return status;
1680         }
1681
1682         return ISC_R_SUCCESS;
1683 }
1684
1685 isc_result_t dhcp_pool_lookup (omapi_object_t **lp,
1686                                omapi_object_t *id, omapi_object_t *ref)
1687 {
1688         omapi_value_t *tv = (omapi_value_t *)0;
1689         isc_result_t status;
1690         struct pool *pool;
1691
1692         /* Can't look up pools yet. */
1693
1694         /* If we get to here without finding a pool, no valid key was
1695            specified. */
1696         if (!*lp)
1697                 return ISC_R_NOKEYS;
1698         return ISC_R_SUCCESS;
1699 }
1700
1701 isc_result_t dhcp_pool_create (omapi_object_t **lp,
1702                                omapi_object_t *id)
1703 {
1704         return ISC_R_NOTIMPLEMENTED;
1705 }
1706
1707 isc_result_t dhcp_pool_remove (omapi_object_t *lp,
1708                                omapi_object_t *id)
1709 {
1710         return ISC_R_NOTIMPLEMENTED;
1711 }
1712
1713 isc_result_t dhcp_class_set_value  (omapi_object_t *h,
1714                                     omapi_object_t *id,
1715                                     omapi_data_string_t *name,
1716                                     omapi_typed_data_t *value)
1717 {
1718         struct class *class;
1719         isc_result_t status;
1720         int foo;
1721
1722         if (h -> type != dhcp_type_class)
1723                 return ISC_R_INVALIDARG;
1724         class = (struct class *)h;
1725
1726         /* No values to set yet. */
1727
1728         /* Try to find some inner object that can take the value. */
1729         if (h -> inner && h -> inner -> type -> set_value) {
1730                 status = ((*(h -> inner -> type -> set_value))
1731                           (h -> inner, id, name, value));
1732                 if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED)
1733                         return status;
1734         }
1735                           
1736         return ISC_R_UNKNOWNATTRIBUTE;
1737 }
1738
1739
1740 isc_result_t dhcp_class_get_value (omapi_object_t *h, omapi_object_t *id,
1741                                    omapi_data_string_t *name,
1742                                    omapi_value_t **value)
1743 {
1744         struct class *class;
1745         isc_result_t status;
1746
1747         if (h -> type != dhcp_type_class)
1748                 return ISC_R_INVALIDARG;
1749         class = (struct class *)h;
1750
1751         /* No values to get yet. */
1752
1753         /* Try to find some inner object that can provide the value. */
1754         if (h -> inner && h -> inner -> type -> get_value) {
1755                 status = ((*(h -> inner -> type -> get_value))
1756                           (h -> inner, id, name, value));
1757                 if (status == ISC_R_SUCCESS)
1758                         return status;
1759         }
1760         return ISC_R_UNKNOWNATTRIBUTE;
1761 }
1762
1763 isc_result_t dhcp_class_destroy (omapi_object_t *h, const char *file, int line)
1764 {
1765         struct class *class;
1766         isc_result_t status;
1767         int i;
1768
1769         if (h -> type != dhcp_type_class && h -> type != dhcp_type_subclass)
1770                 return ISC_R_INVALIDARG;
1771         class = (struct class *)h;
1772
1773 #if defined (DEBUG_MEMORY_LEAKAGE) || \
1774                 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1775         if (class -> nic)
1776                 class_dereference (&class -> nic, file, line);
1777         if (class -> superclass)
1778                 class_dereference (&class -> superclass, file, line);
1779         if (class -> name) {
1780                 dfree (class -> name, file, line);
1781                 class -> name = (char *)0;
1782         }
1783         if (class -> billed_leases) {
1784                 for (i = 0; i < class -> lease_limit; i++) {
1785                         if (class -> billed_leases [i]) {
1786                                 lease_dereference (&class -> billed_leases [i],
1787                                                    file, line);
1788                         }
1789                 }
1790                 dfree (class -> billed_leases, file, line);
1791                 class -> billed_leases = (struct lease **)0;
1792         }
1793         if (class -> hash) {
1794                 class_free_hash_table (&class -> hash, file, line);
1795                 class -> hash = (class_hash_t *)0;
1796         }
1797         data_string_forget (&class -> hash_string, file, line);
1798
1799         if (class -> expr)
1800                 expression_dereference (&class -> expr, file, line);
1801         if (class -> submatch)
1802                 expression_dereference (&class -> submatch, file, line);
1803         if (class -> group)
1804                 group_dereference (&class -> group, file, line);
1805         if (class -> statements)
1806                 executable_statement_dereference (&class -> statements,
1807                                                   file, line);
1808         if (class -> superclass)
1809                 class_dereference (&class -> superclass, file, line);
1810 #endif
1811
1812         return ISC_R_SUCCESS;
1813 }
1814
1815 isc_result_t dhcp_class_signal_handler (omapi_object_t *h,
1816                                         const char *name, va_list ap)
1817 {
1818         struct class *class;
1819         isc_result_t status;
1820         int updatep = 0;
1821
1822         if (h -> type != dhcp_type_class)
1823                 return ISC_R_INVALIDARG;
1824         class = (struct class *)h;
1825
1826         /* Can't write classs yet. */
1827
1828         /* Try to find some inner object that can take the value. */
1829         if (h -> inner && h -> inner -> type -> signal_handler) {
1830                 status = ((*(h -> inner -> type -> signal_handler))
1831                           (h -> inner, name, ap));
1832                 if (status == ISC_R_SUCCESS)
1833                         return status;
1834         }
1835         if (updatep)
1836                 return ISC_R_SUCCESS;
1837         return ISC_R_NOTFOUND;
1838 }
1839
1840 isc_result_t dhcp_class_stuff_values (omapi_object_t *c,
1841                                       omapi_object_t *id,
1842                                       omapi_object_t *h)
1843 {
1844         struct class *class;
1845         isc_result_t status;
1846
1847         if (h -> type != dhcp_type_class)
1848                 return ISC_R_INVALIDARG;
1849         class = (struct class *)h;
1850
1851         /* Can't stuff class values yet. */
1852
1853         /* Write out the inner object, if any. */
1854         if (h -> inner && h -> inner -> type -> stuff_values) {
1855                 status = ((*(h -> inner -> type -> stuff_values))
1856                           (c, id, h -> inner));
1857                 if (status == ISC_R_SUCCESS)
1858                         return status;
1859         }
1860
1861         return ISC_R_SUCCESS;
1862 }
1863
1864 isc_result_t dhcp_class_lookup (omapi_object_t **lp,
1865                                 omapi_object_t *id, omapi_object_t *ref)
1866 {
1867         omapi_value_t *tv = (omapi_value_t *)0;
1868         isc_result_t status;
1869         struct class *class;
1870
1871         /* Can't look up classs yet. */
1872
1873         /* If we get to here without finding a class, no valid key was
1874            specified. */
1875         if (!*lp)
1876                 return ISC_R_NOKEYS;
1877         return ISC_R_SUCCESS;
1878 }
1879
1880 isc_result_t dhcp_class_create (omapi_object_t **lp,
1881                                 omapi_object_t *id)
1882 {
1883         return ISC_R_NOTIMPLEMENTED;
1884 }
1885
1886 isc_result_t dhcp_class_remove (omapi_object_t *lp,
1887                                 omapi_object_t *id)
1888 {
1889         return ISC_R_NOTIMPLEMENTED;
1890 }
1891
1892 isc_result_t dhcp_subclass_set_value  (omapi_object_t *h,
1893                                        omapi_object_t *id,
1894                                        omapi_data_string_t *name,
1895                                        omapi_typed_data_t *value)
1896 {
1897         struct subclass *subclass;
1898         isc_result_t status;
1899         int foo;
1900
1901         if (h -> type != dhcp_type_subclass)
1902                 return ISC_R_INVALIDARG;
1903         subclass = (struct subclass *)h;
1904
1905         /* No values to set yet. */
1906
1907         /* Try to find some inner object that can take the value. */
1908         if (h -> inner && h -> inner -> type -> set_value) {
1909                 status = ((*(h -> inner -> type -> set_value))
1910                           (h -> inner, id, name, value));
1911                 if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED)
1912                         return status;
1913         }
1914                           
1915         return ISC_R_UNKNOWNATTRIBUTE;
1916 }
1917
1918
1919 isc_result_t dhcp_subclass_get_value (omapi_object_t *h, omapi_object_t *id,
1920                                       omapi_data_string_t *name,
1921                                       omapi_value_t **value)
1922 {
1923         struct subclass *subclass;
1924         isc_result_t status;
1925
1926         if (h -> type != dhcp_type_subclass)
1927                 return ISC_R_INVALIDARG;
1928         subclass = (struct subclass *)h;
1929
1930         /* No values to get yet. */
1931
1932         /* Try to find some inner object that can provide the value. */
1933         if (h -> inner && h -> inner -> type -> get_value) {
1934                 status = ((*(h -> inner -> type -> get_value))
1935                           (h -> inner, id, name, value));
1936                 if (status == ISC_R_SUCCESS)
1937                         return status;
1938         }
1939         return ISC_R_UNKNOWNATTRIBUTE;
1940 }
1941
1942 isc_result_t dhcp_subclass_signal_handler (omapi_object_t *h,
1943                                            const char *name, va_list ap)
1944 {
1945         struct subclass *subclass;
1946         isc_result_t status;
1947         int updatep = 0;
1948
1949         if (h -> type != dhcp_type_subclass)
1950                 return ISC_R_INVALIDARG;
1951         subclass = (struct subclass *)h;
1952
1953         /* Can't write subclasss yet. */
1954
1955         /* Try to find some inner object that can take the value. */
1956         if (h -> inner && h -> inner -> type -> signal_handler) {
1957                 status = ((*(h -> inner -> type -> signal_handler))
1958                           (h -> inner, name, ap));
1959                 if (status == ISC_R_SUCCESS)
1960                         return status;
1961         }
1962         if (updatep)
1963                 return ISC_R_SUCCESS;
1964         return ISC_R_NOTFOUND;
1965 }
1966
1967 isc_result_t dhcp_subclass_stuff_values (omapi_object_t *c,
1968                                          omapi_object_t *id,
1969                                          omapi_object_t *h)
1970 {
1971         struct subclass *subclass;
1972         isc_result_t status;
1973
1974         if (h -> type != dhcp_type_subclass)
1975                 return ISC_R_INVALIDARG;
1976         subclass = (struct subclass *)h;
1977
1978         /* Can't stuff subclass values yet. */
1979
1980         /* Write out the inner object, if any. */
1981         if (h -> inner && h -> inner -> type -> stuff_values) {
1982                 status = ((*(h -> inner -> type -> stuff_values))
1983                           (c, id, h -> inner));
1984                 if (status == ISC_R_SUCCESS)
1985                         return status;
1986         }
1987
1988         return ISC_R_SUCCESS;
1989 }
1990
1991 isc_result_t dhcp_subclass_lookup (omapi_object_t **lp,
1992                                    omapi_object_t *id, omapi_object_t *ref)
1993 {
1994         omapi_value_t *tv = (omapi_value_t *)0;
1995         isc_result_t status;
1996         struct subclass *subclass;
1997
1998         /* Can't look up subclasss yet. */
1999
2000         /* If we get to here without finding a subclass, no valid key was
2001            specified. */
2002         if (!*lp)
2003                 return ISC_R_NOKEYS;
2004         return ISC_R_SUCCESS;
2005 }
2006
2007 isc_result_t dhcp_subclass_create (omapi_object_t **lp,
2008                                    omapi_object_t *id)
2009 {
2010         return ISC_R_NOTIMPLEMENTED;
2011 }
2012
2013 isc_result_t dhcp_subclass_remove (omapi_object_t *lp,
2014                                    omapi_object_t *id)
2015 {
2016         return ISC_R_NOTIMPLEMENTED;
2017 }
2018
2019 isc_result_t binding_scope_set_value (struct binding_scope *scope, int createp,
2020                                       omapi_data_string_t *name,
2021                                       omapi_typed_data_t *value)
2022 {
2023         struct binding *bp;
2024         char *nname;
2025         struct binding_value *nv;
2026         nname = dmalloc (name -> len + 1, MDL);
2027         if (!nname)
2028                 return ISC_R_NOMEMORY;
2029         memcpy (nname, name -> value, name -> len);
2030         nname [name -> len] = 0;
2031         bp = find_binding (scope, nname);
2032         if (!bp && !createp) {
2033                 dfree (nname, MDL);
2034                 return ISC_R_UNKNOWNATTRIBUTE;
2035         } 
2036         if (!value) {
2037                 dfree (nname, MDL);
2038                 if (!bp)
2039                         return ISC_R_UNKNOWNATTRIBUTE;
2040                 binding_value_dereference (&bp -> value, MDL);
2041                 return ISC_R_SUCCESS;
2042         }
2043
2044         nv = (struct binding_value *)0;
2045         if (!binding_value_allocate (&nv, MDL)) {
2046                 dfree (nname, MDL);
2047                 return ISC_R_NOMEMORY;
2048         }
2049         switch (value -> type) {
2050               case omapi_datatype_int:
2051                 nv -> type = binding_numeric;
2052                 nv -> value.intval = value -> u.integer;
2053                 break;
2054
2055               case omapi_datatype_string:
2056               case omapi_datatype_data:
2057                 if (!buffer_allocate (&nv -> value.data.buffer,
2058                                       value -> u.buffer.len, MDL)) {
2059                         binding_value_dereference (&nv, MDL);
2060                         dfree (nname, MDL);
2061                         return ISC_R_NOMEMORY;
2062                 }
2063                 memcpy (&nv -> value.data.buffer -> data [1],
2064                         value -> u.buffer.value, value -> u.buffer.len);
2065                 nv -> value.data.len = value -> u.buffer.len;
2066                 break;
2067
2068               case omapi_datatype_object:
2069                 binding_value_dereference (&nv, MDL);
2070                 dfree (nname, MDL);
2071                 return ISC_R_INVALIDARG;
2072         }
2073
2074         if (!bp) {
2075                 bp = dmalloc (sizeof *bp, MDL);
2076                 if (!bp) {
2077                         binding_value_dereference (&nv, MDL);
2078                         dfree (nname, MDL);
2079                         return ISC_R_NOMEMORY;
2080                 }
2081                 memset (bp, 0, sizeof *bp);
2082                 bp -> name = nname;
2083                 nname = (char *)0;
2084                 bp -> next = scope -> bindings;
2085                 scope -> bindings = bp;
2086         } else {
2087                 if (bp -> value)
2088                         binding_value_dereference (&bp -> value, MDL);
2089                 dfree (nname, MDL);
2090         }
2091         binding_value_reference (&bp -> value, nv, MDL);
2092         binding_value_dereference (&nv, MDL);
2093         return ISC_R_SUCCESS;
2094 }
2095
2096 isc_result_t binding_scope_get_value (omapi_value_t **value,
2097                                       struct binding_scope *scope,
2098                                       omapi_data_string_t *name)
2099 {
2100         struct binding *bp;
2101         omapi_typed_data_t *td;
2102         isc_result_t status;
2103         char *nname;
2104         nname = dmalloc (name -> len + 1, MDL);
2105         if (!nname)
2106                 return ISC_R_NOMEMORY;
2107         memcpy (nname, name -> value, name -> len);
2108         nname [name -> len] = 0;
2109         bp = find_binding (scope, nname);
2110         dfree (nname, MDL);
2111         if (!bp)
2112                 return ISC_R_UNKNOWNATTRIBUTE;
2113         if (!bp -> value)
2114                 return ISC_R_UNKNOWNATTRIBUTE;
2115
2116         switch (bp -> value -> type) {
2117               case binding_boolean:
2118                 td = (omapi_typed_data_t *)0;
2119                 status = omapi_typed_data_new (MDL, &td, omapi_datatype_int,
2120                                                bp -> value -> value.boolean);
2121                 break;
2122
2123               case binding_numeric:
2124                 td = (omapi_typed_data_t *)0;
2125                 status = omapi_typed_data_new (MDL, &td, omapi_datatype_int,
2126                                                (int)
2127                                                bp -> value -> value.intval);
2128                 break;
2129
2130               case binding_data:
2131                 td = (omapi_typed_data_t *)0;
2132                 status = omapi_typed_data_new (MDL, &td, omapi_datatype_data,
2133                                                bp -> value -> value.data.len);
2134                 if (status != ISC_R_SUCCESS)
2135                         return status;
2136                 memcpy (&td -> u.buffer.value [0],
2137                         bp -> value -> value.data.data,
2138                         bp -> value -> value.data.len);
2139                 break;
2140
2141                 /* Can't return values for these two (yet?). */
2142               case binding_dns:
2143               case binding_function:
2144                 return ISC_R_INVALIDARG;
2145
2146               default:
2147                 log_fatal ("Impossible case at %s:%d.", MDL);
2148                 return ISC_R_FAILURE;
2149         }
2150
2151         if (status != ISC_R_SUCCESS)
2152                 return status;
2153         status = omapi_value_new (value, MDL);
2154         if (status != ISC_R_SUCCESS) {
2155                 omapi_typed_data_dereference (&td, MDL);
2156                 return status;
2157         }
2158         
2159         omapi_data_string_reference (&(*value) -> name, name, MDL);
2160         omapi_typed_data_reference (&(*value) -> value, td, MDL);
2161         omapi_typed_data_dereference (&td, MDL);
2162
2163         return ISC_R_SUCCESS;
2164 }
2165
2166 isc_result_t binding_scope_stuff_values (omapi_object_t *c,
2167                                          struct binding_scope *scope)
2168 {
2169         struct binding *bp;
2170         unsigned len;
2171         isc_result_t status;
2172
2173         for (bp = scope -> bindings; bp; bp = bp -> next) {
2174             if (bp -> value) {
2175                 if (bp -> value -> type == binding_dns ||
2176                     bp -> value -> type == binding_function)
2177                         continue;
2178
2179                 /* Stuff the name. */
2180                 len = strlen (bp -> name);
2181                 status = omapi_connection_put_uint16 (c, len);
2182                 if (status != ISC_R_SUCCESS)
2183                     return status;
2184                 status = omapi_connection_copyin (c,
2185                                                   (unsigned char *)bp -> name,
2186                                                   len);
2187                 if (status != ISC_R_SUCCESS)
2188                         return status;
2189
2190                 switch (bp -> value -> type) {
2191                   case binding_boolean:
2192                     status = omapi_connection_put_uint32 (c,
2193                                                           sizeof (u_int32_t));
2194                     if (status != ISC_R_SUCCESS)
2195                         return status;
2196                     status = (omapi_connection_put_uint32
2197                               (c,
2198                                ((u_int32_t)(bp -> value -> value.boolean))));
2199                     break;
2200
2201                   case binding_data:
2202                     status = (omapi_connection_put_uint32
2203                               (c, bp -> value -> value.data.len));
2204                     if (status != ISC_R_SUCCESS)
2205                         return status;
2206                     if (bp -> value -> value.data.len) {
2207                         status = (omapi_connection_copyin
2208                                   (c, bp -> value -> value.data.data,
2209                                    bp -> value -> value.data.len));
2210                         if (status != ISC_R_SUCCESS)
2211                             return status;
2212                     }
2213                     break;
2214
2215                   case binding_numeric:
2216                     status = (omapi_connection_put_uint32
2217                               (c, sizeof (u_int32_t)));
2218                     if (status != ISC_R_SUCCESS)
2219                             return status;
2220                     status = (omapi_connection_put_uint32
2221                               (c, ((u_int32_t)
2222                                    (bp -> value -> value.intval))));
2223                     break;
2224
2225
2226                     /* NOTREACHED */
2227                   case binding_dns:
2228                   case binding_function:
2229                     break;
2230                 }
2231             }
2232         }
2233         return ISC_R_SUCCESS;
2234 }
2235
2236 /* vim: set tabstop=8: */