Home | History | Annotate | Line # | Download | only in omapip
      1 /*	$NetBSD: message.c,v 1.3 2022/04/03 01:10:59 christos Exp $	*/
      2 
      3 /* message.c
      4 
      5    Subroutines for dealing with message objects. */
      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: message.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_message,
     39 		    omapi_message_object_t, omapi_type_message)
     40 
     41 omapi_message_object_t *omapi_registered_messages;
     42 
     43 isc_result_t omapi_message_new (omapi_object_t **o, const char *file, int line)
     44 {
     45 	omapi_message_object_t *m;
     46 	omapi_object_t *g;
     47 	isc_result_t status;
     48 
     49 	m = (omapi_message_object_t *)0;
     50 	status = omapi_message_allocate (&m, file, line);
     51 	if (status != ISC_R_SUCCESS)
     52 		return status;
     53 
     54 	g = (omapi_object_t *)0;
     55 	status = omapi_generic_new (&g, file, line);
     56 	if (status != ISC_R_SUCCESS) {
     57 		dfree (m, file, line);
     58 		return status;
     59 	}
     60 	status = omapi_object_reference (&m -> inner, g, file, line);
     61 	if (status != ISC_R_SUCCESS) {
     62 		omapi_object_dereference ((omapi_object_t **)&m, file, line);
     63 		omapi_object_dereference (&g, file, line);
     64 		return status;
     65 	}
     66 	status = omapi_object_reference (&g -> outer,
     67 					 (omapi_object_t *)m, file, line);
     68 
     69 	if (status != ISC_R_SUCCESS) {
     70 		omapi_object_dereference ((omapi_object_t **)&m, file, line);
     71 		omapi_object_dereference (&g, file, line);
     72 		return status;
     73 	}
     74 
     75 	status = omapi_object_reference (o, (omapi_object_t *)m, file, line);
     76 	omapi_message_dereference (&m, file, line);
     77 	omapi_object_dereference (&g, file, line);
     78 	if (status != ISC_R_SUCCESS)
     79 		return status;
     80 
     81 	return status;
     82 }
     83 
     84 isc_result_t omapi_message_set_value (omapi_object_t *h,
     85 				      omapi_object_t *id,
     86 				      omapi_data_string_t *name,
     87 				      omapi_typed_data_t *value)
     88 {
     89 	omapi_message_object_t *m;
     90 	isc_result_t status;
     91 
     92 	if (h -> type != omapi_type_message)
     93 		return DHCP_R_INVALIDARG;
     94 	m = (omapi_message_object_t *)h;
     95 
     96 	/* Can't set authlen. */
     97 
     98 	/* Can set authenticator, but the value must be typed data. */
     99 	if (!omapi_ds_strcmp (name, "authenticator")) {
    100 		if (m -> authenticator)
    101 			omapi_typed_data_dereference (&m -> authenticator,
    102 						      MDL);
    103 		omapi_typed_data_reference (&m -> authenticator, value, MDL);
    104 		return ISC_R_SUCCESS;
    105 
    106 	} else if (!omapi_ds_strcmp (name, "object")) {
    107 		if (value -> type != omapi_datatype_object)
    108 			return DHCP_R_INVALIDARG;
    109 		if (m -> object)
    110 			omapi_object_dereference (&m -> object, MDL);
    111 		omapi_object_reference (&m -> object, value -> u.object, MDL);
    112 		return ISC_R_SUCCESS;
    113 
    114 	} else if (!omapi_ds_strcmp (name, "notify-object")) {
    115 		if (value -> type != omapi_datatype_object)
    116 			return DHCP_R_INVALIDARG;
    117 		if (m -> notify_object)
    118 			omapi_object_dereference (&m -> notify_object, MDL);
    119 		omapi_object_reference (&m -> notify_object,
    120 					value -> u.object, MDL);
    121 		return ISC_R_SUCCESS;
    122 
    123 	/* Can set authid, but it has to be an integer. */
    124 	} else if (!omapi_ds_strcmp (name, "authid")) {
    125 		if (value -> type != omapi_datatype_int)
    126 			return DHCP_R_INVALIDARG;
    127 		m -> authid = value -> u.integer;
    128 		return ISC_R_SUCCESS;
    129 
    130 	/* Can set op, but it has to be an integer. */
    131 	} else if (!omapi_ds_strcmp (name, "op")) {
    132 		if (value -> type != omapi_datatype_int)
    133 			return DHCP_R_INVALIDARG;
    134 		m -> op = value -> u.integer;
    135 		return ISC_R_SUCCESS;
    136 
    137 	/* Handle also has to be an integer. */
    138 	} else if (!omapi_ds_strcmp (name, "handle")) {
    139 		if (value -> type != omapi_datatype_int)
    140 			return DHCP_R_INVALIDARG;
    141 		m -> h = value -> u.integer;
    142 		return ISC_R_SUCCESS;
    143 
    144 	/* Transaction ID has to be an integer. */
    145 	} else if (!omapi_ds_strcmp (name, "id")) {
    146 		if (value -> type != omapi_datatype_int)
    147 			return DHCP_R_INVALIDARG;
    148 		m -> id = value -> u.integer;
    149 		return ISC_R_SUCCESS;
    150 
    151 	/* Remote transaction ID has to be an integer. */
    152 	} else if (!omapi_ds_strcmp (name, "rid")) {
    153 		if (value -> type != omapi_datatype_int)
    154 			return DHCP_R_INVALIDARG;
    155 		m -> rid = value -> u.integer;
    156 		return ISC_R_SUCCESS;
    157 	}
    158 
    159 	/* Try to find some inner object that can take the value. */
    160 	if (h -> inner && h -> inner -> type -> set_value) {
    161 		status = ((*(h -> inner -> type -> set_value))
    162 			  (h -> inner, id, name, value));
    163 		if (status == ISC_R_SUCCESS)
    164 			return status;
    165 	}
    166 
    167 	return ISC_R_NOTFOUND;
    168 }
    169 
    170 isc_result_t omapi_message_get_value (omapi_object_t *h,
    171 				      omapi_object_t *id,
    172 				      omapi_data_string_t *name,
    173 				      omapi_value_t **value)
    174 {
    175 	omapi_message_object_t *m;
    176 	if (h -> type != omapi_type_message)
    177 		return DHCP_R_INVALIDARG;
    178 	m = (omapi_message_object_t *)h;
    179 
    180 	/* Look for values that are in the message data structure. */
    181 	if (!omapi_ds_strcmp (name, "authlen"))
    182 		return omapi_make_int_value (value, name, (int)m -> authlen,
    183 					     MDL);
    184 	else if (!omapi_ds_strcmp (name, "authenticator")) {
    185 		if (m -> authenticator)
    186 			return omapi_make_value (value, name,
    187 						 m -> authenticator, MDL);
    188 		else
    189 			return ISC_R_NOTFOUND;
    190 	} else if (!omapi_ds_strcmp (name, "authid")) {
    191 		return omapi_make_int_value (value,
    192 					     name, (int)m -> authid, MDL);
    193 	} else if (!omapi_ds_strcmp (name, "op")) {
    194 		return omapi_make_int_value (value, name, (int)m -> op, MDL);
    195 	} else if (!omapi_ds_strcmp (name, "handle")) {
    196 		return omapi_make_int_value (value, name, (int)m -> h, MDL);
    197 	} else if (!omapi_ds_strcmp (name, "id")) {
    198 		return omapi_make_int_value (value, name, (int)m -> id, MDL);
    199 	} else if (!omapi_ds_strcmp (name, "rid")) {
    200 		return omapi_make_int_value (value, name, (int)m -> rid, MDL);
    201 	}
    202 
    203 	/* See if there's an inner object that has the value. */
    204 	if (h -> inner && h -> inner -> type -> get_value)
    205 		return (*(h -> inner -> type -> get_value))
    206 			(h -> inner, id, name, value);
    207 	return ISC_R_NOTFOUND;
    208 }
    209 
    210 isc_result_t omapi_message_destroy (omapi_object_t *h,
    211 				    const char *file, int line)
    212 {
    213 	omapi_message_object_t *m;
    214 	if (h -> type != omapi_type_message)
    215 		return DHCP_R_INVALIDARG;
    216 	m = (omapi_message_object_t *)h;
    217 	if (m -> authenticator) {
    218 		omapi_typed_data_dereference (&m -> authenticator, file, line);
    219 	}
    220 	if (!m -> prev && omapi_registered_messages != m)
    221 		omapi_message_unregister (h);
    222 	if (m -> id_object)
    223 		omapi_object_dereference (&m -> id_object, file, line);
    224 	if (m -> object)
    225 		omapi_object_dereference (&m -> object, file, line);
    226 	if (m -> notify_object)
    227 		omapi_object_dereference (&m -> notify_object, file, line);
    228 	if (m -> protocol_object)
    229 		omapi_protocol_dereference (&m -> protocol_object, file, line);
    230 	return ISC_R_SUCCESS;
    231 }
    232 
    233 isc_result_t omapi_message_signal_handler (omapi_object_t *h,
    234 					   const char *name, va_list ap)
    235 {
    236 	omapi_message_object_t *m;
    237 	if (h -> type != omapi_type_message)
    238 		return DHCP_R_INVALIDARG;
    239 	m = (omapi_message_object_t *)h;
    240 
    241 	if (!strcmp (name, "status")) {
    242 		if (m -> notify_object &&
    243 		    m -> notify_object -> type -> signal_handler)
    244 			return ((m -> notify_object -> type -> signal_handler))
    245 				(m -> notify_object, name, ap);
    246 		else if (m -> object && m -> object -> type -> signal_handler)
    247 			return ((m -> object -> type -> signal_handler))
    248 				(m -> object, name, ap);
    249 	}
    250 	if (h -> inner && h -> inner -> type -> signal_handler)
    251 		return (*(h -> inner -> type -> signal_handler)) (h -> inner,
    252 								  name, ap);
    253 	return ISC_R_NOTFOUND;
    254 }
    255 
    256 /* Write all the published values associated with the object through the
    257    specified connection. */
    258 
    259 isc_result_t omapi_message_stuff_values (omapi_object_t *c,
    260 					 omapi_object_t *id,
    261 					 omapi_object_t *m)
    262 {
    263 	if (m -> type != omapi_type_message)
    264 		return DHCP_R_INVALIDARG;
    265 
    266 	if (m -> inner && m -> inner -> type -> stuff_values)
    267 		return (*(m -> inner -> type -> stuff_values)) (c, id,
    268 								m -> inner);
    269 	return ISC_R_SUCCESS;
    270 }
    271 
    272 isc_result_t omapi_message_register (omapi_object_t *mo)
    273 {
    274 	omapi_message_object_t *m;
    275 
    276 	if (mo -> type != omapi_type_message)
    277 		return DHCP_R_INVALIDARG;
    278 	m = (omapi_message_object_t *)mo;
    279 
    280 	/* Already registered? */
    281 	if (m -> prev || m -> next || omapi_registered_messages == m)
    282 		return DHCP_R_INVALIDARG;
    283 
    284 	if (omapi_registered_messages) {
    285 		omapi_object_reference
    286 			((omapi_object_t **)&m -> next,
    287 			 (omapi_object_t *)omapi_registered_messages, MDL);
    288 		omapi_object_reference
    289 			((omapi_object_t **)&omapi_registered_messages -> prev,
    290 			 (omapi_object_t *)m, MDL);
    291 		omapi_object_dereference
    292 			((omapi_object_t **)&omapi_registered_messages, MDL);
    293 	}
    294 	omapi_object_reference
    295 		((omapi_object_t **)&omapi_registered_messages,
    296 		 (omapi_object_t *)m, MDL);
    297 	return ISC_R_SUCCESS;;
    298 }
    299 
    300 isc_result_t omapi_message_unregister (omapi_object_t *mo)
    301 {
    302 	omapi_message_object_t *m;
    303 	omapi_message_object_t *n;
    304 
    305 	if (mo -> type != omapi_type_message)
    306 		return DHCP_R_INVALIDARG;
    307 	m = (omapi_message_object_t *)mo;
    308 
    309 	/* Not registered? */
    310 	if (!m -> prev && omapi_registered_messages != m)
    311 		return DHCP_R_INVALIDARG;
    312 
    313 	n = (omapi_message_object_t *)0;
    314 	if (m -> next) {
    315 		omapi_object_reference ((omapi_object_t **)&n,
    316 					(omapi_object_t *)m -> next, MDL);
    317 		omapi_object_dereference ((omapi_object_t **)&m -> next, MDL);
    318 		omapi_object_dereference ((omapi_object_t **)&n -> prev, MDL);
    319 	}
    320 	if (m -> prev) {
    321 		omapi_message_object_t *tmp = (omapi_message_object_t *)0;
    322 		omapi_object_reference ((omapi_object_t **)&tmp,
    323 					(omapi_object_t *)m -> prev, MDL);
    324 		omapi_object_dereference ((omapi_object_t **)&m -> prev, MDL);
    325 		if (tmp -> next)
    326 			omapi_object_dereference
    327 				((omapi_object_t **)&tmp -> next, MDL);
    328 		if (n)
    329 			omapi_object_reference
    330 				((omapi_object_t **)&tmp -> next,
    331 				 (omapi_object_t *)n, MDL);
    332 		omapi_object_dereference ((omapi_object_t **)&tmp, MDL);
    333 	} else {
    334 		omapi_object_dereference
    335 			((omapi_object_t **)&omapi_registered_messages, MDL);
    336 		if (n)
    337 			omapi_object_reference
    338 				((omapi_object_t **)&omapi_registered_messages,
    339 				 (omapi_object_t *)n, MDL);
    340 	}
    341 	if (n)
    342 		omapi_object_dereference ((omapi_object_t **)&n, MDL);
    343 	return ISC_R_SUCCESS;
    344 }
    345 
    346 #ifdef DEBUG_PROTOCOL
    347 const char *omapi_message_op_name(int op) {
    348 	switch (op) {
    349 	case OMAPI_OP_OPEN:    return "OMAPI_OP_OPEN";
    350 	case OMAPI_OP_REFRESH: return "OMAPI_OP_REFRESH";
    351 	case OMAPI_OP_UPDATE:  return "OMAPI_OP_UPDATE";
    352 	case OMAPI_OP_STATUS:  return "OMAPI_OP_STATUS";
    353 	case OMAPI_OP_DELETE:  return "OMAPI_OP_DELETE";
    354 	case OMAPI_OP_NOTIFY:  return "OMAPI_OP_NOTIFY";
    355 	default:               return "(unknown op)";
    356 	}
    357 }
    358 #endif
    359 
    360 static isc_result_t
    361 omapi_message_process_internal (omapi_object_t *, omapi_object_t *);
    362 
    363 isc_result_t omapi_message_process (omapi_object_t *mo, omapi_object_t *po)
    364 {
    365 	isc_result_t status;
    366 #if defined (DEBUG_MEMORY_LEAKAGE) && 0
    367 	unsigned long previous_outstanding = dmalloc_outstanding;
    368 #endif
    369 
    370 	status = omapi_message_process_internal (mo, po);
    371 
    372 #if defined (DEBUG_MEMORY_LEAKAGE) && 0
    373 	log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
    374 		  dmalloc_generation,
    375 		  dmalloc_outstanding - previous_outstanding,
    376 		  dmalloc_outstanding, dmalloc_longterm);
    377 #endif
    378 #if defined (DEBUG_MEMORY_LEAKAGE) && 0
    379 	dmalloc_dump_outstanding ();
    380 #endif
    381 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) && 0
    382 	dump_rc_history ();
    383 #endif
    384 
    385 	return status;
    386 }
    387 
    388 static isc_result_t
    389 omapi_message_process_internal (omapi_object_t *mo, omapi_object_t *po)
    390 {
    391 	omapi_message_object_t *message, *m;
    392 	omapi_object_t *object = (omapi_object_t *)0;
    393 	omapi_value_t *tv = (omapi_value_t *)0;
    394 	unsigned long create, update, exclusive;
    395 	unsigned long wsi;
    396 	isc_result_t status, waitstatus;
    397 	omapi_object_type_t *type;
    398 
    399 	if (mo -> type != omapi_type_message)
    400 		return DHCP_R_INVALIDARG;
    401 	message = (omapi_message_object_t *)mo;
    402 
    403 #ifdef DEBUG_PROTOCOL
    404 	log_debug ("omapi_message_process(): "
    405 		   "op=%s  handle=%#x  id=%#x  rid=%#x",
    406 		   omapi_message_op_name (message -> op),
    407 		   message -> h, message -> id, message -> rid);
    408 #endif
    409 
    410 	if (message -> rid) {
    411 		for (m = omapi_registered_messages; m; m = m -> next)
    412 			if (m -> id == message -> rid)
    413 				break;
    414 		/* If we don't have a real message corresponding to
    415 		   the message ID to which this message claims it is a
    416 		   response, something's fishy. */
    417 		if (!m)
    418 			return ISC_R_NOTFOUND;
    419 		/* The authenticator on responses must match the initial
    420 		   message. */
    421 		if (message -> authid != m -> authid)
    422 			return ISC_R_NOTFOUND;
    423 	} else {
    424 		m = (omapi_message_object_t *)0;
    425 
    426 		/* All messages must have an authenticator, with the exception
    427 		   of messages that are opening a new authenticator. */
    428 		if (omapi_protocol_authenticated(po) &&
    429 		    !message->id_object &&
    430 		    message->op != OMAPI_OP_OPEN) {
    431 			return omapi_protocol_send_status
    432 				(po, message->id_object, DHCP_R_NOKEYS,
    433 				 message->id, "No authenticator on message");
    434 		}
    435 	}
    436 
    437 	switch (message -> op) {
    438 	      case OMAPI_OP_OPEN:
    439 		if (m) {
    440 			return omapi_protocol_send_status
    441 				(po, message->id_object, DHCP_R_INVALIDARG,
    442 				 message->id, "OPEN can't be a response");
    443 		}
    444 
    445 		/* Get the type of the requested object, if one was
    446 		   specified. */
    447 		status = omapi_get_value_str (mo, message -> id_object,
    448 					      "type", &tv);
    449 		if (status == ISC_R_SUCCESS &&
    450 		    (tv -> value -> type == omapi_datatype_data ||
    451 		     tv -> value -> type == omapi_datatype_string)) {
    452 			for (type = omapi_object_types;
    453 			     type; type = type -> next)
    454 				if (!omapi_td_strcmp (tv -> value,
    455 						      type -> name))
    456 					break;
    457 		} else
    458 			type = (omapi_object_type_t *)0;
    459 		if (tv)
    460 			omapi_value_dereference (&tv, MDL);
    461 
    462 		/* If this object had no authenticator, the requested object
    463 		   must be an authenticator object. */
    464 		if (omapi_protocol_authenticated(po) &&
    465 		    !message->id_object &&
    466 		    type != omapi_type_auth_key) {
    467 			return omapi_protocol_send_status
    468 				(po, message->id_object, DHCP_R_NOKEYS,
    469 				 message->id, "No authenticator on message");
    470 		}
    471 
    472 		/* Get the create flag. */
    473 		status = omapi_get_value_str (mo, message -> id_object,
    474 					      "create", &tv);
    475 		if (status == ISC_R_SUCCESS) {
    476 			status = omapi_get_int_value (&create, tv -> value);
    477 			omapi_value_dereference (&tv, MDL);
    478 			if (status != ISC_R_SUCCESS) {
    479 				return omapi_protocol_send_status
    480 					(po, message -> id_object,
    481 					 status, message -> id,
    482 					 "invalid create flag value");
    483 			}
    484 		} else
    485 			create = 0;
    486 
    487 		/* Get the update flag. */
    488 		status = omapi_get_value_str (mo, message -> id_object,
    489 					      "update", &tv);
    490 		if (status == ISC_R_SUCCESS) {
    491 			status = omapi_get_int_value (&update, tv -> value);
    492 			omapi_value_dereference (&tv, MDL);
    493 			if (status != ISC_R_SUCCESS) {
    494 				return omapi_protocol_send_status
    495 					(po, message -> id_object,
    496 					 status, message -> id,
    497 					 "invalid update flag value");
    498 			}
    499 		} else
    500 			update = 0;
    501 
    502 		/* Get the exclusive flag. */
    503 		status = omapi_get_value_str (mo, message -> id_object,
    504 					      "exclusive", &tv);
    505 		if (status == ISC_R_SUCCESS) {
    506 			status = omapi_get_int_value (&exclusive, tv -> value);
    507 			omapi_value_dereference (&tv, MDL);
    508 			if (status != ISC_R_SUCCESS) {
    509 				return omapi_protocol_send_status
    510 					(po, message -> id_object,
    511 					 status, message -> id,
    512 					 "invalid exclusive flag value");
    513 			}
    514 		} else
    515 			exclusive = 0;
    516 
    517 		/* If we weren't given a type, look the object up with
    518                    the handle. */
    519 		if (!type) {
    520 			if (create) {
    521 				return omapi_protocol_send_status
    522 					(po, message->id_object,
    523 					 DHCP_R_INVALIDARG,
    524 					 message->id,
    525 					 "type required on create");
    526 			}
    527 			goto refresh;
    528 		}
    529 
    530 		/* If the type doesn't provide a lookup method, we can't
    531 		   look up the object. */
    532 		if (!type -> lookup) {
    533 			return omapi_protocol_send_status
    534 				(po, message -> id_object,
    535 				 ISC_R_NOTIMPLEMENTED, message -> id,
    536 				 "unsearchable object type");
    537 		}
    538 
    539 		status = (*(type -> lookup)) (&object, message -> id_object,
    540 					      message -> object);
    541 
    542 		if (status != ISC_R_SUCCESS &&
    543 		    status != ISC_R_NOTFOUND &&
    544 		    status != DHCP_R_NOKEYS) {
    545 			return omapi_protocol_send_status
    546 				(po, message -> id_object,
    547 				 status, message -> id,
    548 				 "object lookup failed");
    549 		}
    550 
    551 		/* If we didn't find the object and we aren't supposed to
    552 		   create it, return an error. */
    553 		if (status == ISC_R_NOTFOUND && !create) {
    554 			return omapi_protocol_send_status
    555 				(po, message -> id_object,
    556 				 ISC_R_NOTFOUND, message -> id,
    557 				 "no object matches specification");
    558 		}
    559 
    560 		/* If we found an object, we're supposed to be creating an
    561 		   object, and we're not supposed to have found an object,
    562 		   return an error. */
    563 		if (status == ISC_R_SUCCESS && create && exclusive) {
    564 			omapi_object_dereference (&object, MDL);
    565 			return omapi_protocol_send_status
    566 				(po, message -> id_object,
    567 				 ISC_R_EXISTS, message -> id,
    568 				 "specified object already exists");
    569 		}
    570 
    571 		/* If we're creating the object, do it now. */
    572 		if (!object) {
    573 			status = omapi_object_create (&object,
    574 						      message -> id_object,
    575 						      type);
    576 			if (status != ISC_R_SUCCESS) {
    577 				return omapi_protocol_send_status
    578 					(po, message -> id_object,
    579 					 status, message -> id,
    580 					 "can't create new object");
    581 			}
    582 		}
    583 
    584 		/* If we're updating it, do so now. */
    585 		if (create || update) {
    586 			/* This check does not belong here. */
    587 			if (object -> type == omapi_type_auth_key) {
    588 				omapi_object_dereference (&object, MDL);
    589 				return omapi_protocol_send_status
    590 					(po, message -> id_object,
    591 					 status, message -> id,
    592 					 "can't update object");
    593 			}
    594 
    595 			status = omapi_object_update (object,
    596 						      message -> id_object,
    597 						      message -> object,
    598 						      message -> h);
    599 			if (status != ISC_R_SUCCESS) {
    600 				omapi_object_dereference (&object, MDL);
    601 				return omapi_protocol_send_status
    602 					(po, message -> id_object,
    603 					 status, message -> id,
    604 					 "can't update object");
    605 			}
    606 		}
    607 
    608 		/* If this is an authenticator object, add it to the active
    609 		   set for the connection. */
    610 		if (object -> type == omapi_type_auth_key) {
    611 			omapi_handle_t handle;
    612 			status = omapi_object_handle (&handle, object);
    613 			if (status != ISC_R_SUCCESS) {
    614 				omapi_object_dereference (&object, MDL);
    615 				return omapi_protocol_send_status
    616 					(po, message -> id_object,
    617 					 status, message -> id,
    618 					 "can't select authenticator");
    619 			}
    620 
    621 			status = omapi_protocol_add_auth (po, object, handle);
    622 			if (status != ISC_R_SUCCESS) {
    623 				omapi_object_dereference (&object, MDL);
    624 				return omapi_protocol_send_status
    625 					(po, message -> id_object,
    626 					 status, message -> id,
    627 					 "can't select authenticator");
    628 			}
    629 		}
    630 
    631 		/* Now send the new contents of the object back in
    632 		   response. */
    633 		goto send;
    634 
    635 	      case OMAPI_OP_REFRESH:
    636 	      refresh:
    637 		status = omapi_handle_lookup (&object, message -> h);
    638 		if (status != ISC_R_SUCCESS) {
    639 			return omapi_protocol_send_status
    640 				(po, message -> id_object,
    641 				 status, message -> id,
    642 				 "no matching handle");
    643 		}
    644 	      send:
    645 		status = omapi_protocol_send_update (po, message -> id_object,
    646 						     message -> id, object);
    647 		omapi_object_dereference (&object, MDL);
    648 		return status;
    649 
    650 	      case OMAPI_OP_UPDATE:
    651 		if (m && m -> object) {
    652 			status = omapi_object_reference (&object, m -> object,
    653 									MDL);
    654 		} else {
    655 			status = omapi_handle_lookup (&object, message -> h);
    656 			if (status != ISC_R_SUCCESS) {
    657 				return omapi_protocol_send_status
    658 					(po, message -> id_object,
    659 					 status, message -> id,
    660 					 "no matching handle");
    661 			}
    662 		}
    663 
    664 		if (object -> type == omapi_type_auth_key ||
    665 		    (object -> inner &&
    666 		     object -> inner -> type == omapi_type_auth_key)) {
    667 			if (!m) {
    668 				omapi_object_dereference (&object, MDL);
    669 				return omapi_protocol_send_status
    670 					(po, message -> id_object,
    671 					 status, message -> id,
    672 					 "cannot update authenticator");
    673 			}
    674 
    675 			status = omapi_protocol_add_auth (po, object,
    676 							  message -> h);
    677 		} else {
    678 			status = omapi_object_update (object,
    679 						      message -> id_object,
    680 						      message -> object,
    681 						      message -> h);
    682 		}
    683 		if (status != ISC_R_SUCCESS) {
    684 			omapi_object_dereference (&object, MDL);
    685 			if (!message -> rid)
    686 				return omapi_protocol_send_status
    687 					(po, message -> id_object,
    688 					 status, message -> id,
    689 					 "can't update object");
    690 			if (m)
    691 				omapi_signal ((omapi_object_t *)m,
    692 					      "status", status,
    693 					      (omapi_typed_data_t *)0);
    694 			return ISC_R_SUCCESS;
    695 		}
    696 		if (!message -> rid)
    697 			status = omapi_protocol_send_status
    698 				(po, message -> id_object, ISC_R_SUCCESS,
    699 				 message -> id, (char *)0);
    700 		if (m) {
    701 			omapi_signal ((omapi_object_t *)m,
    702 				      "status", ISC_R_SUCCESS,
    703 				      (omapi_typed_data_t *)0);
    704 			omapi_message_unregister ((omapi_object_t *)m);
    705 		}
    706 
    707 		omapi_object_dereference (&object, MDL);
    708 
    709 		return status;
    710 
    711 	      case OMAPI_OP_NOTIFY:
    712 		return omapi_protocol_send_status
    713 			(po, message -> id_object, ISC_R_NOTIMPLEMENTED,
    714 			 message -> id, "notify not implemented yet");
    715 
    716 	      case OMAPI_OP_STATUS:
    717 		/* The return status of a request. */
    718 		if (!m)
    719 			return ISC_R_UNEXPECTED;
    720 
    721 		/* Get the wait status. */
    722 		status = omapi_get_value_str (mo, message -> id_object,
    723 					      "result", &tv);
    724 		if (status == ISC_R_SUCCESS) {
    725 			status = omapi_get_int_value (&wsi, tv -> value);
    726 			waitstatus = wsi;
    727 			omapi_value_dereference (&tv, MDL);
    728 			if (status != ISC_R_SUCCESS)
    729 				waitstatus = ISC_R_UNEXPECTED;
    730 		} else
    731 			waitstatus = ISC_R_UNEXPECTED;
    732 
    733 		status = omapi_get_value_str (mo, message -> id_object,
    734 					      "message", &tv);
    735 		omapi_signal ((omapi_object_t *)m, "status", waitstatus, tv);
    736 		if (status == ISC_R_SUCCESS)
    737 			omapi_value_dereference (&tv, MDL);
    738 
    739 		omapi_message_unregister((omapi_object_t *)m);
    740 
    741 		return ISC_R_SUCCESS;
    742 
    743 	      case OMAPI_OP_DELETE:
    744 		status = omapi_handle_lookup (&object, message -> h);
    745 		if (status != ISC_R_SUCCESS) {
    746 			return omapi_protocol_send_status
    747 				(po, message -> id_object,
    748 				 status, message -> id,
    749 				 "no matching handle");
    750 		}
    751 
    752 		if (!object -> type -> remove)
    753 			return omapi_protocol_send_status
    754 				(po, message -> id_object,
    755 				 ISC_R_NOTIMPLEMENTED, message -> id,
    756 				 "no remove method for object");
    757 
    758 		status = (*(object -> type -> remove)) (object,
    759 							message -> id_object);
    760 		omapi_object_dereference (&object, MDL);
    761 
    762 		return omapi_protocol_send_status (po, message -> id_object,
    763 						   status, message -> id,
    764 						   (char *)0);
    765 	}
    766 	return ISC_R_NOTIMPLEMENTED;
    767 }
    768