xref: /netbsd-src/external/mpl/dhcp/dist/omapip/message.c (revision f407d9293b6650aa8c33d6a995f797bb6aaefd90)
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@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 
OMAPI_OBJECT_ALLOC(omapi_message,omapi_message_object_t,omapi_type_message)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 
omapi_message_set_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_typed_data_t * value)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 
omapi_message_get_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_value_t ** value)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 
omapi_message_destroy(omapi_object_t * h,const char * file,int line)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 
omapi_message_signal_handler(omapi_object_t * h,const char * name,va_list ap)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 
omapi_message_stuff_values(omapi_object_t * c,omapi_object_t * id,omapi_object_t * m)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 
omapi_message_register(omapi_object_t * mo)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 
omapi_message_unregister(omapi_object_t * mo)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
omapi_message_op_name(int op)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 
omapi_message_process(omapi_object_t * mo,omapi_object_t * po)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
omapi_message_process_internal(omapi_object_t * mo,omapi_object_t * po)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