3 Functions supporting the object management protocol... */
6 * Copyright (c) 2009,2012 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 1999-2003 by Internet Software Consortium
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * Internet Systems Consortium, Inc.
24 * Redwood City, CA 94063
26 * https://www.isc.org/
28 * This software has been written for Internet Systems Consortium
29 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
30 * To learn more about Internet Systems Consortium, see
31 * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
32 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
33 * ``http://www.nominum.com''.
38 #include <omapip/omapip_p.h>
40 OMAPI_OBJECT_ALLOC (omapi_protocol
, omapi_protocol_object_t
,
42 OMAPI_OBJECT_ALLOC (omapi_protocol_listener
, omapi_protocol_listener_object_t
,
43 omapi_type_protocol_listener
)
45 isc_result_t
omapi_protocol_connect (omapi_object_t
*h
,
46 const char *server_name
,
50 isc_result_t rstatus
, status
;
51 omapi_protocol_object_t
*obj
;
54 log_debug ("omapi_protocol_connect(%s port=%d)", server_name
, port
);
57 obj
= (omapi_protocol_object_t
*)0;
58 status
= omapi_protocol_allocate (&obj
, MDL
);
59 if (status
!= ISC_R_SUCCESS
)
62 rstatus
= omapi_connect ((omapi_object_t
*)obj
, server_name
, port
);
63 if (rstatus
!= ISC_R_SUCCESS
&& rstatus
!= DHCP_R_INCOMPLETE
) {
64 omapi_protocol_dereference (&obj
, MDL
);
67 status
= omapi_object_reference (&h
-> outer
,
68 (omapi_object_t
*)obj
, MDL
);
69 if (status
!= ISC_R_SUCCESS
) {
70 omapi_protocol_dereference (&obj
, MDL
);
73 status
= omapi_object_reference (&obj
-> inner
, h
, MDL
);
74 if (status
!= ISC_R_SUCCESS
) {
75 omapi_protocol_dereference (&obj
, MDL
);
79 /* If we were passed a default authenticator, store it now. We'll
80 open it once we're connected. */
83 dmalloc (sizeof(omapi_remote_auth_t
), MDL
);
84 if (!obj
-> default_auth
) {
85 omapi_protocol_dereference (&obj
, MDL
);
86 return ISC_R_NOMEMORY
;
89 obj
-> default_auth
-> next
= (omapi_remote_auth_t
*)0;
90 status
= omapi_object_reference (&obj
-> default_auth
-> a
,
92 if (status
!= ISC_R_SUCCESS
) {
93 dfree (obj
-> default_auth
, MDL
);
94 omapi_protocol_dereference (&obj
, MDL
);
99 rstatus
= DHCP_R_INCOMPLETE
;
103 status
= ISC_R_SUCCESS
;
107 omapi_protocol_dereference (&obj
, MDL
);
111 /* Send the protocol introduction message. */
112 isc_result_t
omapi_protocol_send_intro (omapi_object_t
*h
,
117 omapi_protocol_object_t
*p
;
119 #ifdef DEBUG_PROTOCOL
120 log_debug ("omapi_protocol_send_intro()");
123 if (h
-> type
!= omapi_type_protocol
)
124 return DHCP_R_INVALIDARG
;
125 p
= (omapi_protocol_object_t
*)h
;
127 if (!h
-> outer
|| h
-> outer
-> type
!= omapi_type_connection
)
128 return ISC_R_NOTCONNECTED
;
130 status
= omapi_connection_put_uint32 (h
-> outer
, ver
);
131 if (status
!= ISC_R_SUCCESS
)
134 status
= omapi_connection_put_uint32 (h
-> outer
, hsize
);
136 if (status
!= ISC_R_SUCCESS
)
139 /* Require the other end to send an intro - this kicks off the
140 protocol input state machine. */
141 p
-> state
= omapi_protocol_intro_wait
;
142 status
= omapi_connection_require (h
-> outer
, 8);
143 if (status
!= ISC_R_SUCCESS
&& status
!= DHCP_R_NOTYET
)
146 /* Make up an initial transaction ID for this connection. */
147 p
-> next_xid
= random ();
148 return ISC_R_SUCCESS
;
151 #ifdef DEBUG_PROTOCOL
152 extern const char *omapi_message_op_name(int);
153 #endif /* DEBUG_PROTOCOL */
155 isc_result_t
omapi_protocol_send_message (omapi_object_t
*po
,
160 omapi_protocol_object_t
*p
;
162 omapi_message_object_t
*m
, *om
;
163 omapi_remote_auth_t
*ra
;
164 omapi_value_t
*signature
;
168 if (po
-> type
!= omapi_type_protocol
||
169 !po
-> outer
|| po
-> outer
-> type
!= omapi_type_connection
||
170 mo
-> type
!= omapi_type_message
)
171 return DHCP_R_INVALIDARG
;
172 if (omo
&& omo
-> type
!= omapi_type_message
)
173 return DHCP_R_INVALIDARG
;
174 p
= (omapi_protocol_object_t
*)po
;
175 c
= (omapi_object_t
*)(po
-> outer
);
176 m
= (omapi_message_object_t
*)mo
;
177 om
= (omapi_message_object_t
*)omo
;
179 #ifdef DEBUG_PROTOCOL
180 log_debug ("omapi_protocol_send_message(): "
181 "op=%s handle=%#lx id=%#lx rid=%#lx",
182 omapi_message_op_name (m
->op
),
183 (long)(m
-> object
? m
-> object
-> handle
: m
-> handle
),
184 (long)p
-> next_xid
, (long)m
-> rid
);
187 /* Find the authid to use for this message. */
189 for (ra
= p
-> remote_auth_list
; ra
; ra
= ra
-> next
) {
196 return DHCP_R_KEY_UNKNOWN
;
197 } else if (p
-> remote_auth_list
) {
198 ra
= p
-> default_auth
;
200 ra
= (omapi_remote_auth_t
*)0;
204 m
-> authid
= ra
-> remote_handle
;
205 status
= omapi_object_reference (&m
-> id_object
,
207 if (status
!= ISC_R_SUCCESS
)
211 /* Write the ID of the authentication key we're using. */
212 status
= omapi_connection_put_uint32 (c
, ra
? ra
-> remote_handle
: 0);
213 if (status
!= ISC_R_SUCCESS
) {
214 omapi_disconnect (c
, 1);
218 /* Activate the authentication key on the connection. */
221 status
= omapi_set_object_value (c
, (omapi_object_t
*)0,
222 "output-authenticator",
224 if (status
!= ISC_R_SUCCESS
) {
225 omapi_disconnect (c
, 1);
229 status
= omapi_connection_output_auth_length (c
, &auth_len
);
230 if (status
!= ISC_R_SUCCESS
) {
231 omapi_disconnect (c
, 1);
236 /* Write the authenticator length */
237 status
= omapi_connection_put_uint32 (c
, auth_len
);
238 if (status
!= ISC_R_SUCCESS
) {
239 omapi_disconnect (c
, 1);
243 /* Write the opcode. */
244 status
= omapi_connection_put_uint32 (c
, m
-> op
);
245 if (status
!= ISC_R_SUCCESS
) {
246 omapi_disconnect (c
, 1);
250 /* Write the handle. If we've been given an explicit handle, use
251 that. Otherwise, use the handle of the object we're sending.
252 The caller is responsible for arranging for one of these handles
253 to be set (or not). */
254 status
= omapi_connection_put_uint32 (c
, (m
-> h
257 ? m
-> object
-> handle
259 if (status
!= ISC_R_SUCCESS
) {
260 omapi_disconnect (c
, 1);
264 /* Set and write the transaction ID. */
265 m
-> id
= p
-> next_xid
++;
266 status
= omapi_connection_put_uint32 (c
, m
-> id
);
267 if (status
!= ISC_R_SUCCESS
) {
268 omapi_disconnect (c
, 1);
272 /* Write the transaction ID of the message to which this is a
273 response, if there is such a message. */
274 status
= omapi_connection_put_uint32 (c
, om
? om
-> id
: m
-> rid
);
275 if (status
!= ISC_R_SUCCESS
) {
276 omapi_disconnect (c
, 1);
280 /* Stuff out the name/value pairs specific to this message. */
281 status
= omapi_stuff_values (c
, id
, (omapi_object_t
*)m
);
282 if (status
!= ISC_R_SUCCESS
) {
283 omapi_disconnect (c
, 1);
287 /* Write the zero-length name that terminates the list of name/value
288 pairs specific to the message. */
289 status
= omapi_connection_put_uint16 (c
, 0);
290 if (status
!= ISC_R_SUCCESS
) {
291 omapi_disconnect (c
, 1);
295 /* Stuff out all the published name/value pairs in the object that's
296 being sent in the message, if there is one. */
298 status
= omapi_stuff_values (c
, id
, m
-> object
);
299 if (status
!= ISC_R_SUCCESS
) {
300 omapi_disconnect (c
, 1);
305 /* Write the zero-length name that terminates the list of name/value
306 pairs for the associated object. */
307 status
= omapi_connection_put_uint16 (c
, 0);
308 if (status
!= ISC_R_SUCCESS
) {
309 omapi_disconnect (c
, 1);
314 /* Calculate the message signature. */
315 signature
= (omapi_value_t
*)0;
316 status
= omapi_get_value_str (c
, (omapi_object_t
*)0,
317 "output-signature", &signature
);
318 if (status
!= ISC_R_SUCCESS
) {
319 omapi_disconnect (c
, 1);
323 /* Write the authenticator... */
324 status
= (omapi_connection_copyin
325 (c
, signature
-> value
-> u
.buffer
.value
,
326 signature
-> value
-> u
.buffer
.len
));
327 omapi_value_dereference (&signature
, MDL
);
328 if (status
!= ISC_R_SUCCESS
) {
329 omapi_disconnect (c
, 1);
333 /* Dectivate the authentication key on the connection. */
334 status
= omapi_set_value_str (c
, (omapi_object_t
*)0,
335 "output-authenticator",
336 (omapi_typed_data_t
*)0);
337 if (status
!= ISC_R_SUCCESS
) {
338 omapi_disconnect (c
, 1);
344 omapi_protocol_reference (&m
-> protocol_object
, p
, MDL
);
346 return ISC_R_SUCCESS
;
350 isc_result_t
omapi_protocol_signal_handler (omapi_object_t
*h
,
351 const char *name
, va_list ap
)
354 omapi_protocol_object_t
*p
;
356 omapi_message_object_t
*m
;
357 omapi_value_t
*signature
= NULL
;
361 #if defined (DEBUG_MEMORY_LEAKAGE)
362 unsigned long previous_outstanding
= 0xDEADBEEF;
363 unsigned long connect_outstanding
= 0xDEADBEEF;
366 if (h
-> type
!= omapi_type_protocol
) {
367 /* XXX shouldn't happen. Put an assert here? */
368 return ISC_R_UNEXPECTED
;
370 p
= (omapi_protocol_object_t
*)h
;
372 if (!strcmp (name
, "connect")) {
373 #if defined (DEBUG_MEMORY_LEAKAGE)
374 connect_outstanding
= dmalloc_outstanding
;
376 /* Send the introductory message. */
377 status
= omapi_protocol_send_intro
378 (h
, OMAPI_PROTOCOL_VERSION
,
379 sizeof (omapi_protocol_header_t
));
380 if (status
!= ISC_R_SUCCESS
) {
381 omapi_disconnect (p
-> outer
, 1);
384 return ISC_R_SUCCESS
;
387 /* Should only receive these when opening the initial authenticator. */
388 if (!strcmp (name
, "status")) {
389 status
= va_arg (ap
, isc_result_t
);
390 if (status
!= ISC_R_SUCCESS
) {
391 omapi_signal_in (h
-> inner
, "status", status
,
392 (omapi_object_t
*)0);
393 omapi_disconnect (p
-> outer
, 1);
396 return omapi_signal_in (h
-> inner
, "ready");
400 /* If we get a disconnect, dump memory usage. */
401 if (!strcmp (name
, "disconnect")) {
402 #if defined (DEBUG_MEMORY_LEAKAGE)
403 if (connect_outstanding
!= 0xDEADBEEF) {
404 log_info ("generation %ld: %ld new, %ld outstanding, %ld%s",
406 dmalloc_outstanding
- previous_outstanding
,
407 dmalloc_outstanding
, dmalloc_longterm
, " long-term");
410 #if defined (DEBUG_MEMORY_LEAKAGE)
411 dmalloc_dump_outstanding ();
413 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
416 for (m
= omapi_registered_messages
; m
; m
= m
-> next
) {
417 if (m
-> protocol_object
== p
) {
419 omapi_signal (m
-> object
, "disconnect");
424 return ISC_R_SUCCESS
;
427 /* Not a signal we recognize? */
428 if (strcmp (name
, "ready")) {
429 if (p
-> inner
&& p
-> inner
-> type
-> signal_handler
)
430 return (*(p
-> inner
-> type
-> signal_handler
)) (h
,
433 return ISC_R_NOTFOUND
;
436 if (!p
-> outer
|| p
-> outer
-> type
!= omapi_type_connection
)
437 return DHCP_R_INVALIDARG
;
440 /* We get here because we requested that we be woken up after
441 some number of bytes were read, and that number of bytes
442 has in fact been read. */
443 switch (p
-> state
) {
444 case omapi_protocol_intro_wait
:
445 /* Get protocol version and header size in network
447 omapi_connection_get_uint32 (c
, &p
-> protocol_version
);
448 omapi_connection_get_uint32 (c
, &p
-> header_size
);
450 /* We currently only support the current protocol version. */
451 if (p
-> protocol_version
!= OMAPI_PROTOCOL_VERSION
) {
452 omapi_disconnect (c
, 1);
453 return DHCP_R_VERSIONMISMATCH
;
456 if (p
-> header_size
< sizeof (omapi_protocol_header_t
)) {
457 omapi_disconnect (c
, 1);
458 return DHCP_R_PROTOCOLERROR
;
461 if (p
-> default_auth
) {
462 status
= omapi_protocol_send_open
463 (h
, (omapi_object_t
*)0, "authenticator",
464 p
-> default_auth
-> a
,
465 OMAPI_NOTIFY_PROTOCOL
);
466 if (status
!= ISC_R_SUCCESS
) {
467 omapi_disconnect (c
, 1);
471 status
= omapi_signal_in (h
-> inner
, "ready");
475 /* The next thing we're expecting is a message header. */
476 p
-> state
= omapi_protocol_header_wait
;
478 /* Register a need for the number of bytes in a
479 header, and if we already have that many, process
481 if ((omapi_connection_require (c
, p
-> header_size
)) !=
484 /* If we already have the data, fall through. */
486 case omapi_protocol_header_wait
:
487 #if defined (DEBUG_MEMORY_LEAKAGE)
488 if (previous_outstanding
!= 0xDEADBEEF) {
489 log_info ("%s %ld: %ld new, %ld outstanding, %ld%s",
490 "generation", dmalloc_generation
,
491 dmalloc_outstanding
- previous_outstanding
,
492 dmalloc_outstanding
, dmalloc_longterm
,
495 #if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
496 dmalloc_dump_outstanding ();
498 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
501 #if defined (DEBUG_MEMORY_LEAKAGE)
503 previous_outstanding
= dmalloc_outstanding
;
505 status
= omapi_message_new ((omapi_object_t
**)&p
-> message
,
507 if (status
!= ISC_R_SUCCESS
) {
508 omapi_disconnect (c
, 1);
512 p
-> verify_result
= ISC_R_SUCCESS
;
514 /* Swap in the header... */
515 omapi_connection_get_uint32 (c
, &p
-> message
-> authid
);
517 /* Bind the authenticator to the message object. */
518 if (p
-> message
-> authid
) {
519 status
= (omapi_protocol_lookup_auth
520 (&p
-> message
-> id_object
, h
,
521 p
-> message
-> authid
));
522 if (status
!= ISC_R_SUCCESS
)
523 p
-> verify_result
= status
;
525 /* Activate the authentication key. */
526 status
= omapi_set_object_value
527 (c
, (omapi_object_t
*)0, "input-authenticator",
528 p
-> message
-> id_object
);
529 if (status
!= ISC_R_SUCCESS
) {
530 omapi_disconnect (c
, 1);
535 omapi_connection_get_uint32 (c
, &p
-> message
-> authlen
);
536 omapi_connection_get_uint32 (c
, &p
-> message
-> op
);
537 omapi_connection_get_uint32 (c
, &th
);
538 p
-> message
-> h
= th
;
539 omapi_connection_get_uint32 (c
, &p
-> message
-> id
);
540 omapi_connection_get_uint32 (c
, &p
-> message
-> rid
);
542 /* If there was any extra header data, skip over it. */
543 if (p
-> header_size
> sizeof (omapi_protocol_header_t
)) {
544 omapi_connection_copyout
545 (0, c
, (p
-> header_size
-
546 sizeof (omapi_protocol_header_t
)));
549 /* XXX must compute partial signature across the
550 XXX preceding bytes. Also, if authenticator
551 specifies encryption as well as signing, we may
552 have to decrypt the data on the way in. */
554 /* First we read in message-specific values, then object
556 p
-> reading_message_values
= 1;
559 /* The next thing we're expecting is length of the
561 p
-> state
= omapi_protocol_name_length_wait
;
563 /* Wait for a 16-bit length. */
564 if ((omapi_connection_require (c
, 2)) != ISC_R_SUCCESS
)
566 /* If it's already here, fall through. */
568 case omapi_protocol_name_length_wait
:
569 omapi_connection_get_uint16 (c
, &nlen
);
570 /* A zero-length name means that we're done reading name+value
573 /* If we've already read in the object, we are
574 done reading the message, but if we've just
575 finished reading in the values associated
576 with the message, we need to read the
578 if (p
-> reading_message_values
) {
579 p
-> reading_message_values
= 0;
580 goto need_name_length
;
583 /* If the authenticator length is zero, there's no
584 signature to read in, so go straight to processing
586 if (p
-> message
-> authlen
== 0)
589 /* The next thing we're expecting is the
590 message signature. */
591 p
-> state
= omapi_protocol_signature_wait
;
593 /* Wait for the number of bytes specified for
594 the authenticator. If we already have it,
596 if (omapi_connection_require
597 (c
, p
-> message
-> authlen
) == ISC_R_SUCCESS
)
602 /* Allocate a buffer for the name. */
603 status
= (omapi_data_string_new (&p
-> name
, nlen
, MDL
));
604 if (status
!= ISC_R_SUCCESS
) {
605 omapi_disconnect (c
, 1);
606 return ISC_R_NOMEMORY
;
608 p
-> state
= omapi_protocol_name_wait
;
609 if (omapi_connection_require (c
, nlen
) != ISC_R_SUCCESS
)
611 /* If it's already here, fall through. */
613 case omapi_protocol_name_wait
:
614 omapi_connection_copyout (p
-> name
-> value
, c
,
616 /* Wait for a 32-bit length. */
617 p
-> state
= omapi_protocol_value_length_wait
;
618 if ((omapi_connection_require (c
, 4)) != ISC_R_SUCCESS
)
620 /* If it's already here, fall through. */
622 case omapi_protocol_value_length_wait
:
623 omapi_connection_get_uint32 (c
, &vlen
);
625 /* Zero-length values are allowed - if we get one, we
626 don't have to read any data for the value - just
627 get the next one, if there is a next one. */
629 goto insert_new_value
;
631 status
= omapi_typed_data_new (MDL
, &p
-> value
,
634 if (status
!= ISC_R_SUCCESS
) {
635 omapi_disconnect (c
, 1);
636 return ISC_R_NOMEMORY
;
639 p
-> state
= omapi_protocol_value_wait
;
640 if (omapi_connection_require (c
, vlen
) != ISC_R_SUCCESS
)
642 /* If it's already here, fall through. */
644 case omapi_protocol_value_wait
:
645 omapi_connection_copyout (p
-> value
-> u
.buffer
.value
, c
,
646 p
-> value
-> u
.buffer
.len
);
649 if (p
-> reading_message_values
) {
650 status
= (omapi_set_value
651 ((omapi_object_t
*)p
-> message
,
652 p
-> message
-> id_object
,
653 p
-> name
, p
-> value
));
655 if (!p
-> message
-> object
) {
656 /* We need a generic object to hang off of the
658 status
= (omapi_generic_new
659 (&p
-> message
-> object
, MDL
));
660 if (status
!= ISC_R_SUCCESS
) {
661 omapi_disconnect (c
, 1);
665 status
= (omapi_set_value
666 ((omapi_object_t
*)p
-> message
-> object
,
667 p
-> message
-> id_object
,
668 p
-> name
, p
-> value
));
670 if (status
!= ISC_R_SUCCESS
) {
671 omapi_disconnect (c
, 1);
674 omapi_data_string_dereference (&p
-> name
, MDL
);
676 omapi_typed_data_dereference (&p
-> value
, MDL
);
677 goto need_name_length
;
680 case omapi_protocol_signature_wait
:
681 if (p
-> message
-> id_object
) {
682 /* Compute the signature of the message. */
683 status
= omapi_get_value_str (c
, (omapi_object_t
*)0,
686 if (status
!= ISC_R_SUCCESS
) {
687 omapi_disconnect (c
, 1);
691 /* Disable the authentication key on the connection. */
692 status
= omapi_set_value_str (c
, (omapi_object_t
*)0,
693 "input-authenticator",
694 (omapi_typed_data_t
*)0);
695 if (status
!= ISC_R_SUCCESS
) {
696 omapi_value_dereference (&signature
, MDL
);
697 omapi_disconnect (c
, 1);
702 /* Read the authenticator. */
703 status
= omapi_typed_data_new (MDL
,
704 &p
-> message
-> authenticator
,
706 p
-> message
-> authlen
);
708 if (status
!= ISC_R_SUCCESS
) {
709 if (signature
!= NULL
) {
710 omapi_value_dereference (&signature
, MDL
);
712 omapi_disconnect (c
, 1);
713 return ISC_R_NOMEMORY
;
715 omapi_connection_copyout
716 (p
-> message
-> authenticator
-> u
.buffer
.value
, c
,
717 p
-> message
-> authlen
);
719 /* Verify the signature. */
720 if (p
-> message
-> id_object
&&
721 ((signature
-> value
-> u
.buffer
.len
!=
722 p
-> message
-> authlen
) ||
723 (memcmp (signature
-> value
-> u
.buffer
.value
,
724 p
-> message
-> authenticator
-> u
.buffer
.value
,
725 p
-> message
-> authlen
) != 0))) {
726 /* Invalid signature. */
727 p
->verify_result
= DHCP_R_INVALIDKEY
;
730 if (signature
!= NULL
) {
731 omapi_value_dereference (&signature
, MDL
);
734 /* Process the message. */
736 if (p
-> verify_result
!= ISC_R_SUCCESS
) {
737 status
= omapi_protocol_send_status
738 (h
, (omapi_object_t
*)0, p
-> verify_result
,
739 p
-> message
-> id
, (char *)0);
741 status
= omapi_message_process
742 ((omapi_object_t
*)p
-> message
, h
);
744 if (status
!= ISC_R_SUCCESS
) {
745 omapi_disconnect (c
, 1);
746 return ISC_R_NOMEMORY
;
749 omapi_message_dereference (&p
-> message
, MDL
);
750 #if defined (DEBUG_MEMORY_LEAKAGE)
751 log_info ("generation %ld: %ld new, %ld outstanding, %ld%s",
753 dmalloc_outstanding
- previous_outstanding
,
754 dmalloc_outstanding
, dmalloc_longterm
, " long-term");
756 #if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
757 dmalloc_dump_outstanding ();
759 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
762 #if defined (DEBUG_MEMORY_LEAKAGE)
763 previous_outstanding
= 0xDEADBEEF;
765 /* Now wait for the next message. */
769 /* XXX should never get here. Assertion? */
772 return ISC_R_SUCCESS
;
775 isc_result_t
omapi_protocol_add_auth (omapi_object_t
*po
,
777 omapi_handle_t handle
)
779 omapi_protocol_object_t
*p
;
780 omapi_remote_auth_t
*r
;
783 if (ao
-> type
!= omapi_type_auth_key
&&
784 (!ao
-> inner
|| ao
-> inner
-> type
!= omapi_type_auth_key
))
785 return DHCP_R_INVALIDARG
;
787 if (po
-> type
!= omapi_type_protocol
)
788 return DHCP_R_INVALIDARG
;
789 p
= (omapi_protocol_object_t
*)po
;
791 #ifdef DEBUG_PROTOCOL
792 log_debug ("omapi_protocol_add_auth(name=%s)",
793 ((omapi_auth_key_t
*)ao
) -> name
);
796 if (p
-> verify_auth
) {
797 status
= (p
-> verify_auth
) (po
, (omapi_auth_key_t
*)ao
);
798 if (status
!= ISC_R_SUCCESS
)
802 /* If omapi_protocol_connect() was called with a default
803 authenticator, p -> default_auth will already be set,
804 but p -> remote_auth_list will not yet be initialized. */
805 if (p
-> default_auth
&& !p
-> remote_auth_list
) {
806 if (p
-> default_auth
-> a
!= ao
) {
807 /* Something just went horribly wrong. */
808 omapi_disconnect (p
-> outer
, 1);
809 return ISC_R_UNEXPECTED
;
812 p
-> remote_auth_list
= p
-> default_auth
;
813 p
-> default_auth
-> remote_handle
= handle
;
815 return omapi_signal_in (p
-> inner
, "ready");
818 r
= dmalloc (sizeof(*r
), MDL
);
820 return ISC_R_NOMEMORY
;
822 status
= omapi_object_reference (&r
-> a
, ao
, MDL
);
823 if (status
!= ISC_R_SUCCESS
) {
828 r
-> remote_handle
= handle
;
829 r
-> next
= p
-> remote_auth_list
;
830 p
-> remote_auth_list
= r
;
832 return ISC_R_SUCCESS
;
835 isc_result_t
omapi_protocol_lookup_auth (omapi_object_t
**a
,
837 omapi_handle_t handle
)
839 omapi_protocol_object_t
*p
;
840 omapi_remote_auth_t
*r
;
842 if (po
-> type
!= omapi_type_protocol
)
843 return DHCP_R_INVALIDARG
;
844 p
= (omapi_protocol_object_t
*)po
;
846 for (r
= p
-> remote_auth_list
; r
; r
= r
-> next
)
847 if (r
-> remote_handle
== handle
)
848 return omapi_object_reference (a
, r
-> a
, MDL
);
850 return DHCP_R_KEY_UNKNOWN
;
853 isc_result_t
omapi_protocol_set_value (omapi_object_t
*h
,
855 omapi_data_string_t
*name
,
856 omapi_typed_data_t
*value
)
858 omapi_protocol_object_t
*p
;
859 omapi_remote_auth_t
*r
;
861 if (h
-> type
!= omapi_type_protocol
)
862 return DHCP_R_INVALIDARG
;
863 p
= (omapi_protocol_object_t
*)h
;
865 if (omapi_ds_strcmp (name
, "default-authenticator") == 0) {
866 if (!value
|| value
-> type
!= omapi_datatype_object
)
867 return DHCP_R_INVALIDARG
;
869 if (!value
-> u
.object
) {
870 p
-> default_auth
= (omapi_remote_auth_t
*)0;
872 for (r
= p
-> remote_auth_list
; r
; r
= r
-> next
)
873 if (r
-> a
== value
-> u
.object
)
877 return DHCP_R_KEY_UNKNOWN
;
879 p
-> default_auth
= r
;
882 return ISC_R_SUCCESS
;
885 if (h
-> inner
&& h
-> inner
-> type
-> set_value
)
886 return (*(h
-> inner
-> type
-> set_value
))
887 (h
-> inner
, id
, name
, value
);
888 return ISC_R_NOTFOUND
;
891 isc_result_t
omapi_protocol_get_value (omapi_object_t
*h
,
893 omapi_data_string_t
*name
,
894 omapi_value_t
**value
)
896 omapi_protocol_object_t
*p
;
898 if (h
-> type
!= omapi_type_protocol
)
899 return DHCP_R_INVALIDARG
;
900 p
= (omapi_protocol_object_t
*)h
;
902 if (omapi_ds_strcmp (name
, "default-authenticator") == 0) {
903 if (!p
-> default_auth
)
904 return ISC_R_NOTFOUND
;
906 return omapi_make_object_value (value
, name
,
907 p
-> default_auth
-> a
, MDL
);
910 if (h
-> inner
&& h
-> inner
-> type
-> get_value
)
911 return (*(h
-> inner
-> type
-> get_value
))
912 (h
-> inner
, id
, name
, value
);
913 return ISC_R_NOTFOUND
;
916 isc_result_t
omapi_protocol_destroy (omapi_object_t
*h
,
917 const char *file
, int line
)
919 omapi_protocol_object_t
*p
;
920 if (h
-> type
!= omapi_type_protocol
)
921 return DHCP_R_INVALIDARG
;
922 p
= (omapi_protocol_object_t
*)h
;
924 omapi_message_dereference (&p
-> message
, file
, line
);
926 /* This will happen if: 1) A default authenticator is supplied to
927 omapi_protocol_connect(), and 2) something goes wrong before
928 the authenticator can be opened. */
929 if (p
-> default_auth
&& !p
-> remote_auth_list
)
930 dfree (p
-> default_auth
, file
, line
);
932 while (p
-> remote_auth_list
) {
933 omapi_remote_auth_t
*r
= p
-> remote_auth_list
;
934 p
-> remote_auth_list
= p
-> remote_auth_list
-> next
;
935 omapi_object_dereference (&r
-> a
, file
, line
);
936 dfree (r
, file
, line
);
938 return ISC_R_SUCCESS
;
941 /* Write all the published values associated with the object through the
942 specified connection. */
944 isc_result_t
omapi_protocol_stuff_values (omapi_object_t
*c
,
948 if (p
-> type
!= omapi_type_protocol
)
949 return DHCP_R_INVALIDARG
;
951 if (p
-> inner
&& p
-> inner
-> type
-> stuff_values
)
952 return (*(p
-> inner
-> type
-> stuff_values
)) (c
, id
,
954 return ISC_R_SUCCESS
;
957 /* Returns a boolean indicating whether this protocol requires that
958 messages be authenticated or not. */
960 isc_boolean_t
omapi_protocol_authenticated (omapi_object_t
*h
)
962 if (h
-> type
!= omapi_type_protocol
)
963 return isc_boolean_false
;
964 if (((omapi_protocol_object_t
*)h
) -> insecure
)
965 return isc_boolean_false
;
967 return isc_boolean_true
;
970 /* Sets the address and authenticator verification callbacks. The handle
971 is to a listener object, not a protocol object. */
973 isc_result_t
omapi_protocol_configure_security (omapi_object_t
*h
,
974 isc_result_t (*verify_addr
)
977 isc_result_t (*verify_auth
)
981 omapi_protocol_listener_object_t
*l
;
983 if (h
-> outer
&& h
-> outer
-> type
== omapi_type_protocol_listener
)
986 if (h
-> type
!= omapi_type_protocol_listener
)
987 return DHCP_R_INVALIDARG
;
988 l
= (omapi_protocol_listener_object_t
*)h
;
990 l
-> verify_auth
= verify_auth
;
993 if (h
-> outer
!= NULL
) {
994 return omapi_listener_configure_security (h
-> outer
, verify_addr
);
996 return DHCP_R_INVALIDARG
;
1001 /* Set up a listener for the omapi protocol. The handle stored points to
1002 a listener object, not a protocol object. */
1004 isc_result_t
omapi_protocol_listen (omapi_object_t
*h
,
1008 isc_result_t status
;
1009 omapi_protocol_listener_object_t
*obj
;
1011 obj
= (omapi_protocol_listener_object_t
*)0;
1012 status
= omapi_protocol_listener_allocate (&obj
, MDL
);
1013 if (status
!= ISC_R_SUCCESS
)
1016 status
= omapi_object_reference (&h
-> outer
,
1017 (omapi_object_t
*)obj
, MDL
);
1018 if (status
!= ISC_R_SUCCESS
) {
1019 omapi_protocol_listener_dereference (&obj
, MDL
);
1022 status
= omapi_object_reference (&obj
-> inner
, h
, MDL
);
1023 if (status
!= ISC_R_SUCCESS
) {
1024 omapi_protocol_listener_dereference (&obj
, MDL
);
1028 /* What a terrible default. */
1029 obj
-> insecure
= 1;
1031 status
= omapi_listen ((omapi_object_t
*)obj
, port
, max
);
1032 omapi_protocol_listener_dereference (&obj
, MDL
);
1036 /* Signal handler for protocol listener - if we get a connect signal,
1037 create a new protocol connection, otherwise pass the signal down. */
1039 isc_result_t
omapi_protocol_listener_signal (omapi_object_t
*o
,
1040 const char *name
, va_list ap
)
1042 isc_result_t status
;
1044 omapi_protocol_object_t
*obj
;
1045 omapi_protocol_listener_object_t
*p
;
1047 if (!o
|| o
-> type
!= omapi_type_protocol_listener
)
1048 return DHCP_R_INVALIDARG
;
1049 p
= (omapi_protocol_listener_object_t
*)o
;
1051 /* Not a signal we recognize? */
1052 if (strcmp (name
, "connect")) {
1053 if (p
-> inner
&& p
-> inner
-> type
-> signal_handler
)
1054 return (*(p
-> inner
-> type
-> signal_handler
))
1055 (p
-> inner
, name
, ap
);
1056 return ISC_R_NOTFOUND
;
1059 c
= va_arg (ap
, omapi_object_t
*);
1060 if (!c
|| c
-> type
!= omapi_type_connection
)
1061 return DHCP_R_INVALIDARG
;
1063 obj
= (omapi_protocol_object_t
*)0;
1064 status
= omapi_protocol_allocate (&obj
, MDL
);
1065 if (status
!= ISC_R_SUCCESS
)
1068 obj
-> verify_auth
= p
-> verify_auth
;
1069 obj
-> insecure
= p
-> insecure
;
1071 status
= omapi_object_reference (&obj
-> outer
, c
, MDL
);
1072 if (status
!= ISC_R_SUCCESS
) {
1074 omapi_protocol_dereference (&obj
, MDL
);
1075 omapi_disconnect (c
, 1);
1079 status
= omapi_object_reference (&c
-> inner
,
1080 (omapi_object_t
*)obj
, MDL
);
1081 if (status
!= ISC_R_SUCCESS
)
1084 /* Send the introductory message. */
1085 status
= omapi_protocol_send_intro ((omapi_object_t
*)obj
,
1086 OMAPI_PROTOCOL_VERSION
,
1087 sizeof (omapi_protocol_header_t
));
1088 if (status
!= ISC_R_SUCCESS
)
1091 omapi_protocol_dereference (&obj
, MDL
);
1095 isc_result_t
omapi_protocol_listener_set_value (omapi_object_t
*h
,
1097 omapi_data_string_t
*name
,
1098 omapi_typed_data_t
*value
)
1100 if (h
-> type
!= omapi_type_protocol_listener
)
1101 return DHCP_R_INVALIDARG
;
1103 if (h
-> inner
&& h
-> inner
-> type
-> set_value
)
1104 return (*(h
-> inner
-> type
-> set_value
))
1105 (h
-> inner
, id
, name
, value
);
1106 return ISC_R_NOTFOUND
;
1109 isc_result_t
omapi_protocol_listener_get_value (omapi_object_t
*h
,
1111 omapi_data_string_t
*name
,
1112 omapi_value_t
**value
)
1114 if (h
-> type
!= omapi_type_protocol_listener
)
1115 return DHCP_R_INVALIDARG
;
1117 if (h
-> inner
&& h
-> inner
-> type
-> get_value
)
1118 return (*(h
-> inner
-> type
-> get_value
))
1119 (h
-> inner
, id
, name
, value
);
1120 return ISC_R_NOTFOUND
;
1123 isc_result_t
omapi_protocol_listener_destroy (omapi_object_t
*h
,
1124 const char *file
, int line
)
1126 if (h
-> type
!= omapi_type_protocol_listener
)
1127 return DHCP_R_INVALIDARG
;
1128 return ISC_R_SUCCESS
;
1131 /* Write all the published values associated with the object through the
1132 specified connection. */
1134 isc_result_t
omapi_protocol_listener_stuff (omapi_object_t
*c
,
1138 if (p
-> type
!= omapi_type_protocol_listener
)
1139 return DHCP_R_INVALIDARG
;
1141 if (p
-> inner
&& p
-> inner
-> type
-> stuff_values
)
1142 return (*(p
-> inner
-> type
-> stuff_values
)) (c
, id
,
1144 return ISC_R_SUCCESS
;
1147 isc_result_t
omapi_protocol_send_status (omapi_object_t
*po
,
1149 isc_result_t waitstatus
,
1150 unsigned rid
, const char *msg
)
1152 isc_result_t status
;
1153 omapi_message_object_t
*message
= (omapi_message_object_t
*)0;
1156 if (po
-> type
!= omapi_type_protocol
)
1157 return DHCP_R_INVALIDARG
;
1159 status
= omapi_message_new ((omapi_object_t
**)&message
, MDL
);
1160 if (status
!= ISC_R_SUCCESS
)
1162 mo
= (omapi_object_t
*)message
;
1164 status
= omapi_set_int_value (mo
, (omapi_object_t
*)0,
1165 "op", OMAPI_OP_STATUS
);
1166 if (status
!= ISC_R_SUCCESS
) {
1167 omapi_message_dereference (&message
, MDL
);
1171 status
= omapi_set_int_value (mo
, (omapi_object_t
*)0,
1173 if (status
!= ISC_R_SUCCESS
) {
1174 omapi_message_dereference (&message
, MDL
);
1178 status
= omapi_set_int_value (mo
, (omapi_object_t
*)0,
1179 "result", (int)waitstatus
);
1180 if (status
!= ISC_R_SUCCESS
) {
1181 omapi_message_dereference (&message
, MDL
);
1185 /* If a message has been provided, send it. */
1187 status
= omapi_set_string_value (mo
, (omapi_object_t
*)0,
1189 if (status
!= ISC_R_SUCCESS
) {
1190 omapi_message_dereference (&message
, MDL
);
1195 status
= omapi_protocol_send_message (po
, id
, mo
, (omapi_object_t
*)0);
1196 omapi_message_dereference (&message
, MDL
);
1200 /* The OMAPI_NOTIFY_PROTOCOL flag will cause the notify-object for the
1201 message to be set to the protocol object. This is used when opening
1202 the default authenticator. */
1204 isc_result_t
omapi_protocol_send_open (omapi_object_t
*po
,
1207 omapi_object_t
*object
,
1210 isc_result_t status
;
1211 omapi_message_object_t
*message
= (omapi_message_object_t
*)0;
1214 if (po
-> type
!= omapi_type_protocol
)
1215 return DHCP_R_INVALIDARG
;
1217 status
= omapi_message_new ((omapi_object_t
**)&message
, MDL
);
1218 mo
= (omapi_object_t
*)message
;
1220 if (status
== ISC_R_SUCCESS
)
1221 status
= omapi_set_int_value (mo
, (omapi_object_t
*)0,
1222 "op", OMAPI_OP_OPEN
);
1224 if (status
== ISC_R_SUCCESS
)
1225 status
= omapi_set_object_value (mo
, (omapi_object_t
*)0,
1228 if ((flags
& OMAPI_CREATE
) && (status
== ISC_R_SUCCESS
))
1229 status
= omapi_set_boolean_value (mo
, (omapi_object_t
*)0,
1232 if ((flags
& OMAPI_UPDATE
) && (status
== ISC_R_SUCCESS
))
1233 status
= omapi_set_boolean_value (mo
, (omapi_object_t
*)0,
1236 if ((flags
& OMAPI_EXCL
) && (status
== ISC_R_SUCCESS
))
1237 status
= omapi_set_boolean_value (mo
, (omapi_object_t
*)0,
1240 if ((flags
& OMAPI_NOTIFY_PROTOCOL
) && (status
== ISC_R_SUCCESS
))
1241 status
= omapi_set_object_value (mo
, (omapi_object_t
*)0,
1242 "notify-object", po
);
1244 if (type
&& (status
== ISC_R_SUCCESS
))
1245 status
= omapi_set_string_value (mo
, (omapi_object_t
*)0,
1248 if (status
== ISC_R_SUCCESS
)
1249 status
= omapi_message_register (mo
);
1251 if (status
== ISC_R_SUCCESS
) {
1252 status
= omapi_protocol_send_message (po
, id
, mo
,
1253 (omapi_object_t
*)0);
1254 if (status
!= ISC_R_SUCCESS
)
1255 omapi_message_unregister (mo
);
1259 omapi_message_dereference (&message
, MDL
);
1264 isc_result_t
omapi_protocol_send_update (omapi_object_t
*po
,
1267 omapi_object_t
*object
)
1269 isc_result_t status
;
1270 omapi_message_object_t
*message
= (omapi_message_object_t
*)0;
1273 if (po
-> type
!= omapi_type_protocol
)
1274 return DHCP_R_INVALIDARG
;
1276 status
= omapi_message_new ((omapi_object_t
**)&message
, MDL
);
1277 if (status
!= ISC_R_SUCCESS
)
1279 mo
= (omapi_object_t
*)message
;
1281 status
= omapi_set_int_value (mo
, (omapi_object_t
*)0,
1282 "op", OMAPI_OP_UPDATE
);
1283 if (status
!= ISC_R_SUCCESS
) {
1284 omapi_message_dereference (&message
, MDL
);
1289 omapi_handle_t handle
;
1290 status
= omapi_set_int_value (mo
, (omapi_object_t
*)0,
1292 if (status
!= ISC_R_SUCCESS
) {
1293 omapi_message_dereference (&message
, MDL
);
1297 status
= omapi_object_handle (&handle
, object
);
1298 if (status
!= ISC_R_SUCCESS
) {
1299 omapi_message_dereference (&message
, MDL
);
1302 status
= omapi_set_int_value (mo
, (omapi_object_t
*)0,
1303 "handle", (int)handle
);
1304 if (status
!= ISC_R_SUCCESS
) {
1305 omapi_message_dereference (&message
, MDL
);
1310 status
= omapi_set_object_value (mo
, (omapi_object_t
*)0,
1312 if (status
!= ISC_R_SUCCESS
) {
1313 omapi_message_dereference (&message
, MDL
);
1317 status
= omapi_protocol_send_message (po
, id
, mo
, (omapi_object_t
*)0);
1318 omapi_message_dereference (&message
, MDL
);