Home | History | Annotate | Line # | Download | only in omapip
      1 /*	$NetBSD: protocol.c,v 1.3 2022/04/03 01:10:59 christos Exp $	*/
      2 
      3 /* protocol.c
      4 
      5    Functions supporting the object management protocol... */
      6 
      7 /*
      8  * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
      9  * Copyright (c) 1999-2003 by Internet Software Consortium
     10  *
     11  * This Source Code Form is subject to the terms of the Mozilla Public
     12  * License, v. 2.0. If a copy of the MPL was not distributed with this
     13  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
     16  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     17  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     18  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     20  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     21  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     22  *
     23  *   Internet Systems Consortium, Inc.
     24  *   PO Box 360
     25  *   Newmarket, NH 03857 USA
     26  *   <info (at) isc.org>
     27  *   https://www.isc.org/
     28  *
     29  */
     30 
     31 #include <sys/cdefs.h>
     32 __RCSID("$NetBSD: protocol.c,v 1.3 2022/04/03 01:10:59 christos 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