xref: /minix/external/bsd/dhcp/dist/omapip/protocol.c (revision fb9c64b2)
1 /*	$NetBSD: protocol.c,v 1.1.1.3 2014/07/12 11:58:00 spz Exp $	*/
2 /* protocol.c
3 
4    Functions supporting the object management protocol... */
5 
6 /*
7  * Copyright (c) 2009,2012,2014 by Internet Systems Consortium, Inc. ("ISC")
8  * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
9  * Copyright (c) 1999-2003 by Internet Software Consortium
10  *
11  * Permission to use, copy, modify, and distribute this software for any
12  * purpose with or without fee is hereby granted, provided that the above
13  * copyright notice and this permission notice appear in all copies.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
18  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  *   Internet Systems Consortium, Inc.
24  *   950 Charter Street
25  *   Redwood City, CA 94063
26  *   <info@isc.org>
27  *   https://www.isc.org/
28  *
29  */
30 
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: protocol.c,v 1.1.1.3 2014/07/12 11:58:00 spz Exp $");
33 
34 #include "dhcpd.h"
35 
36 #include <omapip/omapip_p.h>
37 
38 OMAPI_OBJECT_ALLOC (omapi_protocol, omapi_protocol_object_t,
39 		    omapi_type_protocol)
40 OMAPI_OBJECT_ALLOC (omapi_protocol_listener, omapi_protocol_listener_object_t,
41 		    omapi_type_protocol_listener)
42 
43 isc_result_t omapi_protocol_connect (omapi_object_t *h,
44 				     const char *server_name,
45 				     unsigned port,
46 				     omapi_object_t *a)
47 {
48 	isc_result_t rstatus, status;
49 	omapi_protocol_object_t *obj;
50 
51 #ifdef DEBUG_PROTOCOL
52 	log_debug ("omapi_protocol_connect(%s port=%d)", server_name, port);
53 #endif
54 
55 	obj = (omapi_protocol_object_t *)0;
56 	status = omapi_protocol_allocate (&obj, MDL);
57 	if (status != ISC_R_SUCCESS)
58 		return status;
59 
60 	rstatus = omapi_connect ((omapi_object_t *)obj, server_name, port);
61 	if (rstatus != ISC_R_SUCCESS && rstatus != DHCP_R_INCOMPLETE) {
62 		omapi_protocol_dereference (&obj, MDL);
63 		return rstatus;
64 	}
65 	status = omapi_object_reference (&h -> outer,
66 					 (omapi_object_t *)obj, MDL);
67 	if (status != ISC_R_SUCCESS) {
68 		omapi_protocol_dereference (&obj, MDL);
69 		return status;
70 	}
71 	status = omapi_object_reference (&obj -> inner, h, MDL);
72 	if (status != ISC_R_SUCCESS) {
73 		omapi_protocol_dereference (&obj, MDL);
74 		return status;
75 	}
76 
77 	/* If we were passed a default authenticator, store it now.  We'll
78 	   open it once we're connected. */
79 	if (a) {
80 		obj -> default_auth =
81 			dmalloc (sizeof(omapi_remote_auth_t), MDL);
82 		if (!obj -> default_auth) {
83 			omapi_protocol_dereference (&obj, MDL);
84 			return ISC_R_NOMEMORY;
85 		}
86 
87 		obj -> default_auth -> next = (omapi_remote_auth_t *)0;
88 		status = omapi_object_reference (&obj -> default_auth -> a,
89 						 a, MDL);
90 		if (status != ISC_R_SUCCESS) {
91 			dfree (obj -> default_auth, MDL);
92 			omapi_protocol_dereference (&obj, MDL);
93 			return status;
94 		}
95 
96 		obj -> insecure = 0;
97 		rstatus = DHCP_R_INCOMPLETE;
98 	} else {
99 		obj -> insecure = 1;
100 #if 0
101 		status = ISC_R_SUCCESS;
102 #endif
103 	}
104 
105 	omapi_protocol_dereference (&obj, MDL);
106 	return rstatus;
107 }
108 
109 /* Send the protocol introduction message. */
110 isc_result_t omapi_protocol_send_intro (omapi_object_t *h,
111 					unsigned ver,
112 					unsigned hsize)
113 {
114 	isc_result_t status;
115 	omapi_protocol_object_t *p;
116 
117 #ifdef DEBUG_PROTOCOL
118 	log_debug ("omapi_protocol_send_intro()");
119 #endif
120 
121 	if (h -> type != omapi_type_protocol)
122 		return DHCP_R_INVALIDARG;
123 	p = (omapi_protocol_object_t *)h;
124 
125 	if (!h -> outer || h -> outer -> type != omapi_type_connection)
126 		return ISC_R_NOTCONNECTED;
127 
128 	status = omapi_connection_put_uint32 (h -> outer, ver);
129 	if (status != ISC_R_SUCCESS)
130 		return status;
131 
132 	status = omapi_connection_put_uint32 (h -> outer, hsize);
133 
134 	if (status != ISC_R_SUCCESS)
135 		return status;
136 
137 	/* Require the other end to send an intro - this kicks off the
138 	   protocol input state machine. */
139 	p -> state = omapi_protocol_intro_wait;
140 	status = omapi_connection_require (h -> outer, 8);
141 	if (status != ISC_R_SUCCESS && status != DHCP_R_NOTYET)
142 		return status;
143 
144 	/* Make up an initial transaction ID for this connection. */
145 	p -> next_xid = random ();
146 	return ISC_R_SUCCESS;
147 }
148 
149 #ifdef DEBUG_PROTOCOL
150 extern const char *omapi_message_op_name(int);
151 #endif /* DEBUG_PROTOCOL */
152 
153 isc_result_t omapi_protocol_send_message (omapi_object_t *po,
154 					  omapi_object_t *id,
155 					  omapi_object_t *mo,
156 					  omapi_object_t *omo)
157 {
158 	omapi_protocol_object_t *p;
159 	omapi_object_t *c;
160 	omapi_message_object_t *m, *om;
161 	omapi_remote_auth_t *ra;
162 	omapi_value_t *signature;
163 	isc_result_t status;
164 	unsigned auth_len;
165 
166 	if (po -> type != omapi_type_protocol ||
167 	    !po -> outer || po -> outer -> type != omapi_type_connection ||
168 	    mo -> type != omapi_type_message)
169 		return DHCP_R_INVALIDARG;
170 	if (omo && omo -> type != omapi_type_message)
171 		return DHCP_R_INVALIDARG;
172 	p = (omapi_protocol_object_t *)po;
173 	c = (omapi_object_t *)(po -> outer);
174 	m = (omapi_message_object_t *)mo;
175 	om = (omapi_message_object_t *)omo;
176 
177 #ifdef DEBUG_PROTOCOL
178 	log_debug ("omapi_protocol_send_message(): "
179 		   "op=%s  handle=%#lx  id=%#lx  rid=%#lx",
180 		   omapi_message_op_name (m->op),
181 		   (long)(m -> object ? m -> object -> handle : m -> handle),
182 		   (long)p -> next_xid, (long)m -> rid);
183 #endif
184 
185 	/* Find the authid to use for this message. */
186 	if (id) {
187 		for (ra = p -> remote_auth_list; ra; ra = ra -> next) {
188 			if (ra -> a == id) {
189 				break;
190 			}
191 		}
192 
193 		if (!ra)
194 			return DHCP_R_KEY_UNKNOWN;
195 	} else if (p -> remote_auth_list) {
196 		ra = p -> default_auth;
197 	} else {
198 		ra = (omapi_remote_auth_t *)0;
199 	}
200 
201 	if (ra) {
202 		m -> authid = ra -> remote_handle;
203 		status = omapi_object_reference (&m -> id_object,
204 						 ra -> a, MDL);
205 		if (status != ISC_R_SUCCESS)
206 			return status;
207 	}
208 
209 	/* Write the ID of the authentication key we're using. */
210 	status = omapi_connection_put_uint32 (c, ra ? ra -> remote_handle : 0);
211 	if (status != ISC_R_SUCCESS) {
212 		omapi_disconnect (c, 1);
213 		return status;
214 	}
215 
216 	/* Activate the authentication key on the connection. */
217 	auth_len = 0;
218 	if (ra) {
219 		status = omapi_set_object_value (c, (omapi_object_t *)0,
220 						 "output-authenticator",
221 						 ra -> a);
222 		if (status != ISC_R_SUCCESS) {
223 			omapi_disconnect (c, 1);
224 			return status;
225 		}
226 
227 		status = omapi_connection_output_auth_length (c, &auth_len);
228 		if (status != ISC_R_SUCCESS) {
229 			omapi_disconnect (c, 1);
230 			return status;
231 		}
232 	}
233 
234 	/* Write the authenticator length */
235 	status = omapi_connection_put_uint32 (c, auth_len);
236 	if (status != ISC_R_SUCCESS) {
237 		omapi_disconnect (c, 1);
238 		return status;
239 	}
240 
241 	/* Write the opcode. */
242 	status = omapi_connection_put_uint32 (c, m -> op);
243 	if (status != ISC_R_SUCCESS) {
244 		omapi_disconnect (c, 1);
245 		return status;
246 	}
247 
248 	/* Write the handle.  If we've been given an explicit handle, use
249 	   that.   Otherwise, use the handle of the object we're sending.
250 	   The caller is responsible for arranging for one of these handles
251 	   to be set (or not). */
252 	status = omapi_connection_put_uint32 (c, (m -> h
253 						  ? m -> h
254 						  : (m -> object
255 						     ? m -> object -> handle
256 						     : 0)));
257 	if (status != ISC_R_SUCCESS) {
258 		omapi_disconnect (c, 1);
259 		return status;
260 	}
261 
262 	/* Set and write the transaction ID. */
263 	m -> id = p -> next_xid++;
264 	status = omapi_connection_put_uint32 (c, m -> id);
265 	if (status != ISC_R_SUCCESS) {
266 		omapi_disconnect (c, 1);
267 		return status;
268 	}
269 
270 	/* Write the transaction ID of the message to which this is a
271 	   response, if there is such a message. */
272 	status = omapi_connection_put_uint32 (c, om ? om -> id : m -> rid);
273 	if (status != ISC_R_SUCCESS) {
274 		omapi_disconnect (c, 1);
275 		return status;
276 	}
277 
278 	/* Stuff out the name/value pairs specific to this message. */
279 	status = omapi_stuff_values (c, id, (omapi_object_t *)m);
280 	if (status != ISC_R_SUCCESS) {
281 		omapi_disconnect (c, 1);
282 		return status;
283 	}
284 
285 	/* Write the zero-length name that terminates the list of name/value
286 	   pairs specific to the message. */
287 	status = omapi_connection_put_uint16 (c, 0);
288 	if (status != ISC_R_SUCCESS) {
289 		omapi_disconnect (c, 1);
290 		return status;
291 	}
292 
293 	/* Stuff out all the published name/value pairs in the object that's
294 	   being sent in the message, if there is one. */
295 	if (m -> object) {
296 		status = omapi_stuff_values (c, id, m -> object);
297 		if (status != ISC_R_SUCCESS) {
298 			omapi_disconnect (c, 1);
299 			return status;
300 		}
301 	}
302 
303 	/* Write the zero-length name that terminates the list of name/value
304 	   pairs for the associated object. */
305 	status = omapi_connection_put_uint16 (c, 0);
306 	if (status != ISC_R_SUCCESS) {
307 		omapi_disconnect (c, 1);
308 		return status;
309 	}
310 
311 	if (ra) {
312 		/* Calculate the message signature. */
313 		signature = (omapi_value_t *)0;
314 		status = omapi_get_value_str (c, (omapi_object_t *)0,
315 					      "output-signature", &signature);
316 		if (status != ISC_R_SUCCESS) {
317 			omapi_disconnect (c, 1);
318 			return status;
319 		}
320 
321 		/* Write the authenticator... */
322 		status = (omapi_connection_copyin
323 			  (c, signature -> value -> u.buffer.value,
324 			   signature -> value -> u.buffer.len));
325 		omapi_value_dereference (&signature, MDL);
326 		if (status != ISC_R_SUCCESS) {
327 			omapi_disconnect (c, 1);
328 			return status;
329 		}
330 
331 		/* Dectivate the authentication key on the connection. */
332 		status = omapi_set_value_str (c, (omapi_object_t *)0,
333 						 "output-authenticator",
334 						 (omapi_typed_data_t *)0);
335 		if (status != ISC_R_SUCCESS) {
336 			omapi_disconnect (c, 1);
337 			return status;
338 		}
339 	}
340 
341 	if (!omo) {
342 		omapi_protocol_reference (&m -> protocol_object, p, MDL);
343 	}
344 	return ISC_R_SUCCESS;
345 }
346 
347 
348 isc_result_t omapi_protocol_signal_handler (omapi_object_t *h,
349 					    const char *name, va_list ap)
350 {
351 	isc_result_t status;
352 	omapi_protocol_object_t *p;
353 	omapi_object_t *c;
354 	omapi_message_object_t *m;
355 	omapi_value_t *signature = NULL;
356 	u_int16_t nlen;
357 	u_int32_t vlen;
358 	u_int32_t th;
359 #if defined (DEBUG_MEMORY_LEAKAGE)
360 	unsigned long previous_outstanding = 0xDEADBEEF;
361 	unsigned long connect_outstanding = 0xDEADBEEF;
362 #endif
363 
364 	if (h -> type != omapi_type_protocol) {
365 		/* XXX shouldn't happen.   Put an assert here? */
366 		return ISC_R_UNEXPECTED;
367 	}
368 	p = (omapi_protocol_object_t *)h;
369 
370 	if (!strcmp (name, "connect")) {
371 #if defined (DEBUG_MEMORY_LEAKAGE)
372 		connect_outstanding = dmalloc_outstanding;
373 #endif
374 		/* Send the introductory message. */
375 		status = omapi_protocol_send_intro
376 			(h, OMAPI_PROTOCOL_VERSION,
377 			 sizeof (omapi_protocol_header_t));
378 		if (status != ISC_R_SUCCESS) {
379 			omapi_disconnect (p -> outer, 1);
380 			return status;
381 		}
382 		return ISC_R_SUCCESS;
383 	}
384 
385 	/* Should only receive these when opening the initial authenticator. */
386 	if (!strcmp (name, "status")) {
387 		status = va_arg (ap, isc_result_t);
388 		if (status != ISC_R_SUCCESS) {
389 			omapi_signal_in (h -> inner, "status", status,
390 					 (omapi_object_t *)0);
391 			omapi_disconnect (p -> outer, 1);
392 			return status;
393 		} else {
394 			return omapi_signal_in (h -> inner, "ready");
395 		}
396 	}
397 
398 	/* If we get a disconnect, dump memory usage. */
399 	if (!strcmp (name, "disconnect")) {
400 #if defined (DEBUG_MEMORY_LEAKAGE)
401 	    if (connect_outstanding != 0xDEADBEEF) {
402 		log_info ("generation %ld: %ld new, %ld outstanding, %ld%s",
403 			  dmalloc_generation,
404 			  dmalloc_outstanding - previous_outstanding,
405 			  dmalloc_outstanding, dmalloc_longterm, " long-term");
406 	    }
407 #endif
408 #if defined (DEBUG_MEMORY_LEAKAGE)
409 	    dmalloc_dump_outstanding ();
410 #endif
411 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
412 	    dump_rc_history (h);
413 #endif
414 	    for (m = omapi_registered_messages; m; m = m -> next) {
415 		if (m -> protocol_object == p) {
416 		    if (m -> object)
417 			omapi_signal (m -> object, "disconnect");
418 		}
419 	    }
420 
421 	    /* XXX */
422 	    return ISC_R_SUCCESS;
423 	}
424 
425 	/* Not a signal we recognize? */
426 	if (strcmp (name, "ready")) {
427 		if (p -> inner && p -> inner -> type -> signal_handler)
428 			return (*(p -> inner -> type -> signal_handler)) (h,
429 									  name,
430 									  ap);
431 		return ISC_R_NOTFOUND;
432 	}
433 
434 	if (!p -> outer || p -> outer -> type != omapi_type_connection)
435 		return DHCP_R_INVALIDARG;
436 	c = p -> outer;
437 
438 	/* We get here because we requested that we be woken up after
439            some number of bytes were read, and that number of bytes
440            has in fact been read. */
441 	switch (p -> state) {
442 	      case omapi_protocol_intro_wait:
443 		/* Get protocol version and header size in network
444 		   byte order. */
445 		omapi_connection_get_uint32 (c, &p -> protocol_version);
446 		omapi_connection_get_uint32 (c, &p -> header_size);
447 
448 		/* We currently only support the current protocol version. */
449 		if (p -> protocol_version != OMAPI_PROTOCOL_VERSION) {
450 			omapi_disconnect (c, 1);
451 			return DHCP_R_VERSIONMISMATCH;
452 		}
453 
454 		if (p -> header_size < sizeof (omapi_protocol_header_t)) {
455 			omapi_disconnect (c, 1);
456 			return DHCP_R_PROTOCOLERROR;
457 		}
458 
459 		if (p -> default_auth) {
460 			status = omapi_protocol_send_open
461 				(h, (omapi_object_t *)0, "authenticator",
462 				 p -> default_auth -> a,
463 				 OMAPI_NOTIFY_PROTOCOL);
464 			if (status != ISC_R_SUCCESS) {
465 				omapi_disconnect (c, 1);
466 				return status;
467 			}
468 		} else {
469 			status = omapi_signal_in (h -> inner, "ready");
470 		}
471 
472 	      to_header_wait:
473 		/* The next thing we're expecting is a message header. */
474 		p -> state = omapi_protocol_header_wait;
475 
476 		/* Register a need for the number of bytes in a
477 		   header, and if we already have that many, process
478 		   them immediately. */
479 		if ((omapi_connection_require (c, p -> header_size)) !=
480 		    ISC_R_SUCCESS)
481 			break;
482 		/* If we already have the data, fall through. */
483 
484 	      case omapi_protocol_header_wait:
485 #if defined (DEBUG_MEMORY_LEAKAGE)
486 		if (previous_outstanding != 0xDEADBEEF) {
487 			log_info ("%s %ld: %ld new, %ld outstanding, %ld%s",
488 				  "generation", dmalloc_generation,
489 				  dmalloc_outstanding - previous_outstanding,
490 				  dmalloc_outstanding, dmalloc_longterm,
491 				  " long-term");
492 #endif
493 #if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
494 			dmalloc_dump_outstanding ();
495 #endif
496 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
497 			dump_rc_history (h);
498 #endif
499 #if defined (DEBUG_MEMORY_LEAKAGE)
500 		}
501 		previous_outstanding = dmalloc_outstanding;
502 #endif
503 		status = omapi_message_new ((omapi_object_t **)&p -> message,
504 					    MDL);
505 		if (status != ISC_R_SUCCESS) {
506 			omapi_disconnect (c, 1);
507 			return status;
508 		}
509 
510 		p -> verify_result = ISC_R_SUCCESS;
511 
512 		/* Swap in the header... */
513 		omapi_connection_get_uint32 (c, &p -> message -> authid);
514 
515 		/* Bind the authenticator to the message object. */
516 		if (p -> message -> authid) {
517 			status = (omapi_protocol_lookup_auth
518 				  (&p -> message -> id_object, h,
519 				   p -> message -> authid));
520 			if (status != ISC_R_SUCCESS)
521 				p -> verify_result = status;
522 
523 			/* Activate the authentication key. */
524 			status = omapi_set_object_value
525 				(c, (omapi_object_t *)0, "input-authenticator",
526 				 p -> message -> id_object);
527 			if (status != ISC_R_SUCCESS) {
528 				omapi_disconnect (c, 1);
529 				return status;
530 			}
531 		}
532 
533 		omapi_connection_get_uint32 (c, &p -> message -> authlen);
534 		omapi_connection_get_uint32 (c, &p -> message -> op);
535 		omapi_connection_get_uint32 (c, &th);
536 		p -> message -> h = th;
537 		omapi_connection_get_uint32 (c, &p -> message -> id);
538 		omapi_connection_get_uint32 (c, &p -> message -> rid);
539 
540 		/* If there was any extra header data, skip over it. */
541 		if (p -> header_size > sizeof (omapi_protocol_header_t)) {
542 			omapi_connection_copyout
543 				(0, c, (p -> header_size -
544 					sizeof (omapi_protocol_header_t)));
545 		}
546 
547 		/* XXX must compute partial signature across the
548                    XXX preceding bytes.    Also, if authenticator
549 		   specifies encryption as well as signing, we may
550 		   have to decrypt the data on the way in. */
551 
552 		/* First we read in message-specific values, then object
553 		   values. */
554 		p -> reading_message_values = 1;
555 
556 	      need_name_length:
557 		/* The next thing we're expecting is length of the
558 		   first name. */
559 		p -> state = omapi_protocol_name_length_wait;
560 
561 		/* Wait for a 16-bit length. */
562 		if ((omapi_connection_require (c, 2)) != ISC_R_SUCCESS)
563 			break;
564 		/* If it's already here, fall through. */
565 
566 	      case omapi_protocol_name_length_wait:
567 		omapi_connection_get_uint16 (c, &nlen);
568 		/* A zero-length name means that we're done reading name+value
569 		   pairs. */
570 		if (nlen == 0) {
571 			/* If we've already read in the object, we are
572 			   done reading the message, but if we've just
573 			   finished reading in the values associated
574 			   with the message, we need to read the
575 			   object. */
576 			if (p -> reading_message_values) {
577 				p -> reading_message_values = 0;
578 				goto need_name_length;
579 			}
580 
581 			/* If the authenticator length is zero, there's no
582 			   signature to read in, so go straight to processing
583 			   the message. */
584 			if (p -> message -> authlen == 0)
585 				goto message_done;
586 
587 			/* The next thing we're expecting is the
588                            message signature. */
589 			p -> state = omapi_protocol_signature_wait;
590 
591 			/* Wait for the number of bytes specified for
592 			   the authenticator.  If we already have it,
593 			   go read it in. */
594 			if (omapi_connection_require
595 			    (c, p -> message -> authlen) == ISC_R_SUCCESS)
596 				goto signature_wait;
597 			break;
598 		}
599 
600 		/* Allocate a buffer for the name. */
601 		status = (omapi_data_string_new (&p -> name, nlen, MDL));
602 		if (status != ISC_R_SUCCESS) {
603 			omapi_disconnect (c, 1);
604 			return ISC_R_NOMEMORY;
605 		}
606 		p -> state = omapi_protocol_name_wait;
607 		if (omapi_connection_require (c, nlen) != ISC_R_SUCCESS)
608 			break;
609 		/* If it's already here, fall through. */
610 
611 	      case omapi_protocol_name_wait:
612 		omapi_connection_copyout (p -> name -> value, c,
613 					  p -> name -> len);
614 		/* Wait for a 32-bit length. */
615 		p -> state = omapi_protocol_value_length_wait;
616 		if ((omapi_connection_require (c, 4)) != ISC_R_SUCCESS)
617 			break;
618 		/* If it's already here, fall through. */
619 
620 	      case omapi_protocol_value_length_wait:
621 		omapi_connection_get_uint32 (c, &vlen);
622 
623 		/* Zero-length values are allowed - if we get one, we
624 		   don't have to read any data for the value - just
625 		   get the next one, if there is a next one. */
626 		if (!vlen)
627 			goto insert_new_value;
628 
629 		status = omapi_typed_data_new (MDL, &p -> value,
630 					       omapi_datatype_data,
631 					       vlen);
632 		if (status != ISC_R_SUCCESS) {
633 			omapi_disconnect (c, 1);
634 			return ISC_R_NOMEMORY;
635 		}
636 
637 		p -> state = omapi_protocol_value_wait;
638 		if (omapi_connection_require (c, vlen) != ISC_R_SUCCESS)
639 			break;
640 		/* If it's already here, fall through. */
641 
642 	      case omapi_protocol_value_wait:
643 		omapi_connection_copyout (p -> value -> u.buffer.value, c,
644 					  p -> value -> u.buffer.len);
645 
646 	      insert_new_value:
647 		if (p -> reading_message_values) {
648 			status = (omapi_set_value
649 				  ((omapi_object_t *)p -> message,
650 				   p -> message -> id_object,
651 				   p -> name, p -> value));
652 		} else {
653 			if (!p -> message -> object) {
654 				/* We need a generic object to hang off of the
655 				   incoming message. */
656 				status = (omapi_generic_new
657 					  (&p -> message -> object, MDL));
658 				if (status != ISC_R_SUCCESS) {
659 					omapi_disconnect (c, 1);
660 					return status;
661 				}
662 			}
663 			status = (omapi_set_value
664 				  ((omapi_object_t *)p -> message -> object,
665 				   p -> message -> id_object,
666 				   p -> name, p -> value));
667 		}
668 		if (status != ISC_R_SUCCESS) {
669 			omapi_disconnect (c, 1);
670 			return status;
671 		}
672 		omapi_data_string_dereference (&p -> name, MDL);
673 		if (p -> value)
674 			omapi_typed_data_dereference (&p -> value, MDL);
675 		goto need_name_length;
676 
677 	      signature_wait:
678 	      case omapi_protocol_signature_wait:
679 		if (p -> message -> id_object) {
680 			/* Compute the signature of the message. */
681 			status = omapi_get_value_str (c, (omapi_object_t *)0,
682 						      "input-signature",
683 						      &signature);
684 			if (status != ISC_R_SUCCESS) {
685 				omapi_disconnect (c, 1);
686 				return status;
687 			}
688 
689 			/* Disable the authentication key on the connection. */
690 			status = omapi_set_value_str (c, (omapi_object_t *)0,
691 						      "input-authenticator",
692 						      (omapi_typed_data_t *)0);
693 			if (status != ISC_R_SUCCESS) {
694 				omapi_value_dereference (&signature, MDL);
695 				omapi_disconnect (c, 1);
696 				return status;
697 			}
698 		}
699 
700 		/* Read the authenticator. */
701 		status = omapi_typed_data_new (MDL,
702 					       &p -> message -> authenticator,
703 					       omapi_datatype_data,
704 					       p -> message -> authlen);
705 
706 		if (status != ISC_R_SUCCESS) {
707 			if (signature != NULL) {
708 				omapi_value_dereference (&signature, MDL);
709 			}
710 			omapi_disconnect (c, 1);
711 			return ISC_R_NOMEMORY;
712 		}
713 		omapi_connection_copyout
714 			(p -> message -> authenticator -> u.buffer.value, c,
715 			 p -> message -> authlen);
716 
717 		/* Verify the signature. */
718 		if (p -> message -> id_object &&
719 		    ((signature -> value -> u.buffer.len !=
720 		      p -> message -> authlen) ||
721 		     (memcmp (signature -> value -> u.buffer.value,
722 			      p -> message -> authenticator -> u.buffer.value,
723 			      p -> message -> authlen) != 0))) {
724 			/* Invalid signature. */
725 			p->verify_result = DHCP_R_INVALIDKEY;
726 		}
727 
728 		if (signature != NULL) {
729 			omapi_value_dereference (&signature, MDL);
730 		}
731 
732 		/* Process the message. */
733 	      message_done:
734 		if (p -> verify_result != ISC_R_SUCCESS) {
735 			status = omapi_protocol_send_status
736 				(h, (omapi_object_t *)0, p -> verify_result,
737 				 p -> message -> id, (char *)0);
738 		} else {
739 			status = omapi_message_process
740 				((omapi_object_t *)p -> message, h);
741 		}
742 		if (status != ISC_R_SUCCESS) {
743 			omapi_disconnect (c, 1);
744 			return ISC_R_NOMEMORY;
745 		}
746 
747 		omapi_message_dereference (&p -> message, MDL);
748 #if defined (DEBUG_MEMORY_LEAKAGE)
749 		log_info ("generation %ld: %ld new, %ld outstanding, %ld%s",
750 			  dmalloc_generation,
751 			  dmalloc_outstanding - previous_outstanding,
752 			  dmalloc_outstanding, dmalloc_longterm, " long-term");
753 #endif
754 #if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
755 		dmalloc_dump_outstanding ();
756 #endif
757 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
758 		dump_rc_history (h);
759 #endif
760 #if defined (DEBUG_MEMORY_LEAKAGE)
761 		previous_outstanding = 0xDEADBEEF;
762 #endif
763 		/* Now wait for the next message. */
764 		goto to_header_wait;
765 
766 	      default:
767 		/* XXX should never get here.   Assertion? */
768 		break;
769 	}
770 	return ISC_R_SUCCESS;
771 }
772 
773 isc_result_t omapi_protocol_add_auth (omapi_object_t *po,
774 				      omapi_object_t *ao,
775 				      omapi_handle_t handle)
776 {
777 	omapi_protocol_object_t *p;
778 	omapi_remote_auth_t *r;
779 	isc_result_t status;
780 
781 	if (ao -> type != omapi_type_auth_key &&
782 	    (!ao -> inner || ao -> inner -> type != omapi_type_auth_key))
783 		return DHCP_R_INVALIDARG;
784 
785 	if (po -> type != omapi_type_protocol)
786 		return DHCP_R_INVALIDARG;
787 	p = (omapi_protocol_object_t *)po;
788 
789 #ifdef DEBUG_PROTOCOL
790 	log_debug ("omapi_protocol_add_auth(name=%s)",
791 		   ((omapi_auth_key_t *)ao) -> name);
792 #endif
793 
794 	if (p -> verify_auth) {
795 		status = (p -> verify_auth) (po, (omapi_auth_key_t *)ao);
796 		if (status != ISC_R_SUCCESS)
797 			return status;
798 	}
799 
800 	/* If omapi_protocol_connect() was called with a default
801 	   authenticator, p -> default_auth will already be set,
802 	   but p -> remote_auth_list will not yet be initialized. */
803 	if (p -> default_auth && !p -> remote_auth_list) {
804 		if (p -> default_auth -> a != ao) {
805 			/* Something just went horribly wrong. */
806 			omapi_disconnect (p -> outer, 1);
807 			return ISC_R_UNEXPECTED;
808 		}
809 
810 		p -> remote_auth_list = p -> default_auth;
811 		p -> default_auth -> remote_handle = handle;
812 
813 		return omapi_signal_in (p -> inner, "ready");
814 	}
815 
816 	r = dmalloc (sizeof(*r), MDL);
817 	if (!r)
818 		return ISC_R_NOMEMORY;
819 
820 	status = omapi_object_reference (&r -> a, ao, MDL);
821 	if (status != ISC_R_SUCCESS) {
822 		dfree (r, MDL);
823 		return status;
824 	}
825 
826 	r -> remote_handle = handle;
827 	r -> next = p -> remote_auth_list;
828 	p -> remote_auth_list = r;
829 
830 	return ISC_R_SUCCESS;
831 }
832 
833 isc_result_t omapi_protocol_lookup_auth (omapi_object_t **a,
834 					 omapi_object_t *po,
835 					 omapi_handle_t handle)
836 {
837 	omapi_protocol_object_t *p;
838 	omapi_remote_auth_t *r;
839 
840 	if (po -> type != omapi_type_protocol)
841 		return DHCP_R_INVALIDARG;
842 	p = (omapi_protocol_object_t *)po;
843 
844 	for (r = p -> remote_auth_list; r; r = r -> next)
845 		if (r -> remote_handle == handle)
846 			return omapi_object_reference (a, r -> a, MDL);
847 
848 	return DHCP_R_KEY_UNKNOWN;
849 }
850 
851 isc_result_t omapi_protocol_set_value (omapi_object_t *h,
852 				       omapi_object_t *id,
853 				       omapi_data_string_t *name,
854 				       omapi_typed_data_t *value)
855 {
856 	omapi_protocol_object_t *p;
857 	omapi_remote_auth_t *r;
858 
859 	if (h -> type != omapi_type_protocol)
860 		return DHCP_R_INVALIDARG;
861 	p = (omapi_protocol_object_t *)h;
862 
863 	if (omapi_ds_strcmp (name, "default-authenticator") == 0) {
864 		if (!value || value -> type != omapi_datatype_object)
865 			return DHCP_R_INVALIDARG;
866 
867 		if (!value -> u.object) {
868 			p -> default_auth = (omapi_remote_auth_t *)0;
869 		} else {
870 			for (r = p -> remote_auth_list; r; r = r -> next)
871 				if (r -> a == value -> u.object)
872 					break;
873 
874 			if (!r)
875 				return DHCP_R_KEY_UNKNOWN;
876 
877 			p -> default_auth = r;
878 		}
879 
880 		return ISC_R_SUCCESS;
881 	}
882 
883 	if (h -> inner && h -> inner -> type -> set_value)
884 		return (*(h -> inner -> type -> set_value))
885 			(h -> inner, id, name, value);
886 	return ISC_R_NOTFOUND;
887 }
888 
889 isc_result_t omapi_protocol_get_value (omapi_object_t *h,
890 				       omapi_object_t *id,
891 				       omapi_data_string_t *name,
892 				       omapi_value_t **value)
893 {
894 	omapi_protocol_object_t *p;
895 
896 	if (h -> type != omapi_type_protocol)
897 		return DHCP_R_INVALIDARG;
898 	p = (omapi_protocol_object_t *)h;
899 
900 	if (omapi_ds_strcmp (name, "default-authenticator") == 0) {
901 		if (!p -> default_auth)
902 			return ISC_R_NOTFOUND;
903 
904 		return omapi_make_object_value (value, name,
905 						p -> default_auth -> a, MDL);
906 	}
907 
908 	if (h -> inner && h -> inner -> type -> get_value)
909 		return (*(h -> inner -> type -> get_value))
910 			(h -> inner, id, name, value);
911 	return ISC_R_NOTFOUND;
912 }
913 
914 isc_result_t omapi_protocol_destroy (omapi_object_t *h,
915 				     const char *file, int line)
916 {
917 	omapi_protocol_object_t *p;
918 	if (h -> type != omapi_type_protocol)
919 		return DHCP_R_INVALIDARG;
920 	p = (omapi_protocol_object_t *)h;
921 	if (p -> message)
922 		omapi_message_dereference (&p -> message, file, line);
923 
924 	/* This will happen if: 1) A default authenticator is supplied to
925 	   omapi_protocol_connect(), and 2) something goes wrong before
926 	   the authenticator can be opened. */
927 	if (p -> default_auth && !p -> remote_auth_list)
928 		dfree (p -> default_auth, file, line);
929 
930 	while (p -> remote_auth_list) {
931 		omapi_remote_auth_t *r = p -> remote_auth_list;
932 		p -> remote_auth_list =  p -> remote_auth_list -> next;
933 		omapi_object_dereference (&r -> a, file, line);
934 		dfree (r, file, line);
935 	}
936 	return ISC_R_SUCCESS;
937 }
938 
939 /* Write all the published values associated with the object through the
940    specified connection. */
941 
942 isc_result_t omapi_protocol_stuff_values (omapi_object_t *c,
943 					  omapi_object_t *id,
944 					  omapi_object_t *p)
945 {
946 	if (p -> type != omapi_type_protocol)
947 		return DHCP_R_INVALIDARG;
948 
949 	if (p -> inner && p -> inner -> type -> stuff_values)
950 		return (*(p -> inner -> type -> stuff_values)) (c, id,
951 								p -> inner);
952 	return ISC_R_SUCCESS;
953 }
954 
955 /* Returns a boolean indicating whether this protocol requires that
956    messages be authenticated or not. */
957 
958 isc_boolean_t omapi_protocol_authenticated (omapi_object_t *h)
959 {
960 	if (h -> type != omapi_type_protocol)
961 		return isc_boolean_false;
962 	if (((omapi_protocol_object_t *)h) -> insecure)
963 		return isc_boolean_false;
964 	else
965 		return isc_boolean_true;
966 }
967 
968 /* Sets the address and authenticator verification callbacks.  The handle
969    is to a listener object, not a protocol object. */
970 
971 isc_result_t omapi_protocol_configure_security (omapi_object_t *h,
972 						isc_result_t (*verify_addr)
973 						 (omapi_object_t *,
974 						  omapi_addr_t *),
975 						isc_result_t (*verify_auth)
976 						 (omapi_object_t *,
977 						  omapi_auth_key_t *))
978 {
979 	omapi_protocol_listener_object_t *l;
980 
981 	if (h -> outer && h -> outer -> type == omapi_type_protocol_listener)
982 		h = h -> outer;
983 
984 	if (h -> type != omapi_type_protocol_listener)
985 		return DHCP_R_INVALIDARG;
986 	l = (omapi_protocol_listener_object_t *)h;
987 
988 	l -> verify_auth = verify_auth;
989 	l -> insecure = 0;
990 
991 	if (h -> outer != NULL) {
992 		return omapi_listener_configure_security (h -> outer, verify_addr);
993 	} else {
994 		return DHCP_R_INVALIDARG;
995 	}
996 }
997 
998 
999 /* Set up a listener for the omapi protocol.    The handle stored points to
1000    a listener object, not a protocol object. */
1001 
1002 isc_result_t omapi_protocol_listen (omapi_object_t *h,
1003 				    unsigned port,
1004 				    int max)
1005 {
1006 	isc_result_t status;
1007 	omapi_protocol_listener_object_t *obj;
1008 
1009 	obj = (omapi_protocol_listener_object_t *)0;
1010 	status = omapi_protocol_listener_allocate (&obj, MDL);
1011 	if (status != ISC_R_SUCCESS)
1012 		return status;
1013 
1014 	status = omapi_object_reference (&h -> outer,
1015 					 (omapi_object_t *)obj, MDL);
1016 	if (status != ISC_R_SUCCESS) {
1017 		omapi_protocol_listener_dereference (&obj, MDL);
1018 		return status;
1019 	}
1020 	status = omapi_object_reference (&obj -> inner, h, MDL);
1021 	if (status != ISC_R_SUCCESS) {
1022 		omapi_protocol_listener_dereference (&obj, MDL);
1023 		return status;
1024 	}
1025 
1026 	/* What a terrible default. */
1027 	obj -> insecure = 1;
1028 
1029 	status = omapi_listen ((omapi_object_t *)obj, port, max);
1030 	omapi_protocol_listener_dereference (&obj, MDL);
1031 	return status;
1032 }
1033 
1034 /* Signal handler for protocol listener - if we get a connect signal,
1035    create a new protocol connection, otherwise pass the signal down. */
1036 
1037 isc_result_t omapi_protocol_listener_signal (omapi_object_t *o,
1038 					     const char *name, va_list ap)
1039 {
1040 	isc_result_t status;
1041 	omapi_object_t *c;
1042 	omapi_protocol_object_t *obj;
1043 	omapi_protocol_listener_object_t *p;
1044 
1045 	if (!o || o -> type != omapi_type_protocol_listener)
1046 		return DHCP_R_INVALIDARG;
1047 	p = (omapi_protocol_listener_object_t *)o;
1048 
1049 	/* Not a signal we recognize? */
1050 	if (strcmp (name, "connect")) {
1051 		if (p -> inner && p -> inner -> type -> signal_handler)
1052 			return (*(p -> inner -> type -> signal_handler))
1053 				(p -> inner, name, ap);
1054 		return ISC_R_NOTFOUND;
1055 	}
1056 
1057 	c = va_arg (ap, omapi_object_t *);
1058 	if (!c || c -> type != omapi_type_connection)
1059 		return DHCP_R_INVALIDARG;
1060 
1061 	obj = (omapi_protocol_object_t *)0;
1062 	status = omapi_protocol_allocate (&obj, MDL);
1063 	if (status != ISC_R_SUCCESS)
1064 		return status;
1065 
1066 	obj -> verify_auth = p -> verify_auth;
1067 	obj -> insecure = p -> insecure;
1068 
1069 	status = omapi_object_reference (&obj -> outer, c, MDL);
1070 	if (status != ISC_R_SUCCESS) {
1071 	      lose:
1072 		omapi_protocol_dereference (&obj, MDL);
1073 		omapi_disconnect (c, 1);
1074 		return status;
1075 	}
1076 
1077 	status = omapi_object_reference (&c -> inner,
1078 					 (omapi_object_t *)obj, MDL);
1079 	if (status != ISC_R_SUCCESS)
1080 		goto lose;
1081 
1082 	/* Send the introductory message. */
1083 	status = omapi_protocol_send_intro ((omapi_object_t *)obj,
1084 					    OMAPI_PROTOCOL_VERSION,
1085 					    sizeof (omapi_protocol_header_t));
1086 	if (status != ISC_R_SUCCESS)
1087 		goto lose;
1088 
1089 	omapi_protocol_dereference (&obj, MDL);
1090 	return status;
1091 }
1092 
1093 isc_result_t omapi_protocol_listener_set_value (omapi_object_t *h,
1094 						omapi_object_t *id,
1095 						omapi_data_string_t *name,
1096 						omapi_typed_data_t *value)
1097 {
1098 	if (h -> type != omapi_type_protocol_listener)
1099 		return DHCP_R_INVALIDARG;
1100 
1101 	if (h -> inner && h -> inner -> type -> set_value)
1102 		return (*(h -> inner -> type -> set_value))
1103 			(h -> inner, id, name, value);
1104 	return ISC_R_NOTFOUND;
1105 }
1106 
1107 isc_result_t omapi_protocol_listener_get_value (omapi_object_t *h,
1108 						omapi_object_t *id,
1109 						omapi_data_string_t *name,
1110 						omapi_value_t **value)
1111 {
1112 	if (h -> type != omapi_type_protocol_listener)
1113 		return DHCP_R_INVALIDARG;
1114 
1115 	if (h -> inner && h -> inner -> type -> get_value)
1116 		return (*(h -> inner -> type -> get_value))
1117 			(h -> inner, id, name, value);
1118 	return ISC_R_NOTFOUND;
1119 }
1120 
1121 isc_result_t omapi_protocol_listener_destroy (omapi_object_t *h,
1122 					      const char *file, int line)
1123 {
1124 	if (h -> type != omapi_type_protocol_listener)
1125 		return DHCP_R_INVALIDARG;
1126 	return ISC_R_SUCCESS;
1127 }
1128 
1129 /* Write all the published values associated with the object through the
1130    specified connection. */
1131 
1132 isc_result_t omapi_protocol_listener_stuff (omapi_object_t *c,
1133 					    omapi_object_t *id,
1134 					    omapi_object_t *p)
1135 {
1136 	if (p -> type != omapi_type_protocol_listener)
1137 		return DHCP_R_INVALIDARG;
1138 
1139 	if (p -> inner && p -> inner -> type -> stuff_values)
1140 		return (*(p -> inner -> type -> stuff_values)) (c, id,
1141 								p -> inner);
1142 	return ISC_R_SUCCESS;
1143 }
1144 
1145 isc_result_t omapi_protocol_send_status (omapi_object_t *po,
1146 					 omapi_object_t *id,
1147 					 isc_result_t waitstatus,
1148 					 unsigned rid, const char *msg)
1149 {
1150 	isc_result_t status;
1151 	omapi_message_object_t *message = (omapi_message_object_t *)0;
1152 	omapi_object_t *mo;
1153 
1154 	if (po -> type != omapi_type_protocol)
1155 		return DHCP_R_INVALIDARG;
1156 
1157 	status = omapi_message_new ((omapi_object_t **)&message, MDL);
1158 	if (status != ISC_R_SUCCESS)
1159 		return status;
1160 	mo = (omapi_object_t *)message;
1161 
1162 	status = omapi_set_int_value (mo, (omapi_object_t *)0,
1163 				      "op", OMAPI_OP_STATUS);
1164 	if (status != ISC_R_SUCCESS) {
1165 		omapi_message_dereference (&message, MDL);
1166 		return status;
1167 	}
1168 
1169 	status = omapi_set_int_value (mo, (omapi_object_t *)0,
1170 				      "rid", (int)rid);
1171 	if (status != ISC_R_SUCCESS) {
1172 		omapi_message_dereference (&message, MDL);
1173 		return status;
1174 	}
1175 
1176 	status = omapi_set_int_value (mo, (omapi_object_t *)0,
1177 				      "result", (int)waitstatus);
1178 	if (status != ISC_R_SUCCESS) {
1179 		omapi_message_dereference (&message, MDL);
1180 		return status;
1181 	}
1182 
1183 	/* If a message has been provided, send it. */
1184 	if (msg) {
1185 		status = omapi_set_string_value (mo, (omapi_object_t *)0,
1186 						 "message", msg);
1187 		if (status != ISC_R_SUCCESS) {
1188 			omapi_message_dereference (&message, MDL);
1189 			return status;
1190 		}
1191 	}
1192 
1193 	status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0);
1194 	omapi_message_dereference (&message, MDL);
1195 	return status;
1196 }
1197 
1198 /* The OMAPI_NOTIFY_PROTOCOL flag will cause the notify-object for the
1199    message to be set to the protocol object.  This is used when opening
1200    the default authenticator. */
1201 
1202 isc_result_t omapi_protocol_send_open (omapi_object_t *po,
1203 				       omapi_object_t *id,
1204 				       const char *type,
1205 				       omapi_object_t *object,
1206 				       unsigned flags)
1207 {
1208 	isc_result_t status;
1209 	omapi_message_object_t *message = (omapi_message_object_t *)0;
1210 	omapi_object_t *mo;
1211 
1212 	if (po -> type != omapi_type_protocol)
1213 		return DHCP_R_INVALIDARG;
1214 
1215 	status = omapi_message_new ((omapi_object_t **)&message, MDL);
1216 	mo = (omapi_object_t *)message;
1217 
1218 	if (status == ISC_R_SUCCESS)
1219 		status = omapi_set_int_value (mo, (omapi_object_t *)0,
1220 					      "op", OMAPI_OP_OPEN);
1221 
1222 	if (status == ISC_R_SUCCESS)
1223 		status = omapi_set_object_value (mo, (omapi_object_t *)0,
1224 						 "object", object);
1225 
1226 	if ((flags & OMAPI_CREATE) && (status == ISC_R_SUCCESS))
1227 		status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1228 						  "create", 1);
1229 
1230 	if ((flags & OMAPI_UPDATE) && (status == ISC_R_SUCCESS))
1231 		status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1232 						  "update", 1);
1233 
1234 	if ((flags & OMAPI_EXCL) && (status == ISC_R_SUCCESS))
1235 		status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1236 						  "exclusive", 1);
1237 
1238 	if ((flags & OMAPI_NOTIFY_PROTOCOL) && (status == ISC_R_SUCCESS))
1239 		status = omapi_set_object_value (mo, (omapi_object_t *)0,
1240 						 "notify-object", po);
1241 
1242 	if (type && (status == ISC_R_SUCCESS))
1243 		status = omapi_set_string_value (mo, (omapi_object_t *)0,
1244 						 "type", type);
1245 
1246 	if (status == ISC_R_SUCCESS)
1247 		status = omapi_message_register (mo);
1248 
1249 	if (status == ISC_R_SUCCESS) {
1250 		status = omapi_protocol_send_message (po, id, mo,
1251 						      (omapi_object_t *)0);
1252 		if (status != ISC_R_SUCCESS)
1253 			omapi_message_unregister (mo);
1254 	}
1255 
1256 	if (message)
1257 		omapi_message_dereference (&message, MDL);
1258 
1259 	return status;
1260 }
1261 
1262 isc_result_t omapi_protocol_send_update (omapi_object_t *po,
1263 					 omapi_object_t *id,
1264 					 unsigned rid,
1265 					 omapi_object_t *object)
1266 {
1267 	isc_result_t status;
1268 	omapi_message_object_t *message = (omapi_message_object_t *)0;
1269 	omapi_object_t *mo;
1270 
1271 	if (po -> type != omapi_type_protocol)
1272 		return DHCP_R_INVALIDARG;
1273 
1274 	status = omapi_message_new ((omapi_object_t **)&message, MDL);
1275 	if (status != ISC_R_SUCCESS)
1276 		return status;
1277 	mo = (omapi_object_t *)message;
1278 
1279 	status = omapi_set_int_value (mo, (omapi_object_t *)0,
1280 				      "op", OMAPI_OP_UPDATE);
1281 	if (status != ISC_R_SUCCESS) {
1282 		omapi_message_dereference (&message, MDL);
1283 		return status;
1284 	}
1285 
1286 	if (rid) {
1287 		omapi_handle_t handle;
1288 		status = omapi_set_int_value (mo, (omapi_object_t *)0,
1289 					      "rid", (int)rid);
1290 		if (status != ISC_R_SUCCESS) {
1291 			omapi_message_dereference (&message, MDL);
1292 			return status;
1293 		}
1294 
1295 		status = omapi_object_handle (&handle, object);
1296 		if (status != ISC_R_SUCCESS) {
1297 			omapi_message_dereference (&message, MDL);
1298 			return status;
1299 		}
1300 		status = omapi_set_int_value (mo, (omapi_object_t *)0,
1301 					      "handle", (int)handle);
1302 		if (status != ISC_R_SUCCESS) {
1303 			omapi_message_dereference (&message, MDL);
1304 			return status;
1305 		}
1306 	}
1307 
1308 	status = omapi_set_object_value (mo, (omapi_object_t *)0,
1309 					 "object", object);
1310 	if (status != ISC_R_SUCCESS) {
1311 		omapi_message_dereference (&message, MDL);
1312 		return status;
1313 	}
1314 
1315 	status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0);
1316 	omapi_message_dereference (&message, MDL);
1317 	return status;
1318 }
1319