Remove building with NOCRYPTO option
[minix.git] / external / bsd / dhcp / dist / omapip / protocol.c
blob64d86710422543140a4878961894d52d627c2359
1 /* $NetBSD: protocol.c,v 1.1.1.3 2014/07/12 11:58:00 spz Exp $ */
2 /* protocol.c
4 Functions supporting the object management protocol... */
6 /*
7 * Copyright (c) 2009,2012,2014 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 1999-2003 by Internet Software Consortium
11 * Permission to use, copy, modify, and distribute this software for any
12 * purpose with or without fee is hereby granted, provided that the above
13 * copyright notice and this permission notice appear in all copies.
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.
23 * Internet Systems Consortium, Inc.
24 * 950 Charter Street
25 * Redwood City, CA 94063
26 * <info@isc.org>
27 * https://www.isc.org/
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: protocol.c,v 1.1.1.3 2014/07/12 11:58:00 spz Exp $");
34 #include "dhcpd.h"
36 #include <omapip/omapip_p.h>
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)
43 isc_result_t omapi_protocol_connect (omapi_object_t *h,
44 const char *server_name,
45 unsigned port,
46 omapi_object_t *a)
48 isc_result_t rstatus, status;
49 omapi_protocol_object_t *obj;
51 #ifdef DEBUG_PROTOCOL
52 log_debug ("omapi_protocol_connect(%s port=%d)", server_name, port);
53 #endif
55 obj = (omapi_protocol_object_t *)0;
56 status = omapi_protocol_allocate (&obj, MDL);
57 if (status != ISC_R_SUCCESS)
58 return status;
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;
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;
71 status = omapi_object_reference (&obj -> inner, h, MDL);
72 if (status != ISC_R_SUCCESS) {
73 omapi_protocol_dereference (&obj, MDL);
74 return status;
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;
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;
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
105 omapi_protocol_dereference (&obj, MDL);
106 return rstatus;
109 /* Send the protocol introduction message. */
110 isc_result_t omapi_protocol_send_intro (omapi_object_t *h,
111 unsigned ver,
112 unsigned hsize)
114 isc_result_t status;
115 omapi_protocol_object_t *p;
117 #ifdef DEBUG_PROTOCOL
118 log_debug ("omapi_protocol_send_intro()");
119 #endif
121 if (h -> type != omapi_type_protocol)
122 return DHCP_R_INVALIDARG;
123 p = (omapi_protocol_object_t *)h;
125 if (!h -> outer || h -> outer -> type != omapi_type_connection)
126 return ISC_R_NOTCONNECTED;
128 status = omapi_connection_put_uint32 (h -> outer, ver);
129 if (status != ISC_R_SUCCESS)
130 return status;
132 status = omapi_connection_put_uint32 (h -> outer, hsize);
134 if (status != ISC_R_SUCCESS)
135 return status;
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;
144 /* Make up an initial transaction ID for this connection. */
145 p -> next_xid = random ();
146 return ISC_R_SUCCESS;
149 #ifdef DEBUG_PROTOCOL
150 extern const char *omapi_message_op_name(int);
151 #endif /* DEBUG_PROTOCOL */
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)
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;
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;
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
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;
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;
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;
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;
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;
227 status = omapi_connection_output_auth_length (c, &auth_len);
228 if (status != ISC_R_SUCCESS) {
229 omapi_disconnect (c, 1);
230 return status;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
341 if (!omo) {
342 omapi_protocol_reference (&m -> protocol_object, p, MDL);
344 return ISC_R_SUCCESS;
348 isc_result_t omapi_protocol_signal_handler (omapi_object_t *h,
349 const char *name, va_list ap)
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
364 if (h -> type != omapi_type_protocol) {
365 /* XXX shouldn't happen. Put an assert here? */
366 return ISC_R_UNEXPECTED;
368 p = (omapi_protocol_object_t *)h;
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;
382 return ISC_R_SUCCESS;
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");
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");
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");
421 /* XXX */
422 return ISC_R_SUCCESS;
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;
434 if (!p -> outer || p -> outer -> type != omapi_type_connection)
435 return DHCP_R_INVALIDARG;
436 c = p -> outer;
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);
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;
454 if (p -> header_size < sizeof (omapi_protocol_header_t)) {
455 omapi_disconnect (c, 1);
456 return DHCP_R_PROTOCOLERROR;
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;
468 } else {
469 status = omapi_signal_in (h -> inner, "ready");
472 to_header_wait:
473 /* The next thing we're expecting is a message header. */
474 p -> state = omapi_protocol_header_wait;
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. */
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)
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;
510 p -> verify_result = ISC_R_SUCCESS;
512 /* Swap in the header... */
513 omapi_connection_get_uint32 (c, &p -> message -> authid);
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;
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;
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);
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)));
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. */
552 /* First we read in message-specific values, then object
553 values. */
554 p -> reading_message_values = 1;
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;
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. */
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;
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;
587 /* The next thing we're expecting is the
588 message signature. */
589 p -> state = omapi_protocol_signature_wait;
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;
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;
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. */
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. */
620 case omapi_protocol_value_length_wait:
621 omapi_connection_get_uint32 (c, &vlen);
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;
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;
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. */
642 case omapi_protocol_value_wait:
643 omapi_connection_copyout (p -> value -> u.buffer.value, c,
644 p -> value -> u.buffer.len);
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;
663 status = (omapi_set_value
664 ((omapi_object_t *)p -> message -> object,
665 p -> message -> id_object,
666 p -> name, p -> value));
668 if (status != ISC_R_SUCCESS) {
669 omapi_disconnect (c, 1);
670 return status;
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;
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;
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;
700 /* Read the authenticator. */
701 status = omapi_typed_data_new (MDL,
702 &p -> message -> authenticator,
703 omapi_datatype_data,
704 p -> message -> authlen);
706 if (status != ISC_R_SUCCESS) {
707 if (signature != NULL) {
708 omapi_value_dereference (&signature, MDL);
710 omapi_disconnect (c, 1);
711 return ISC_R_NOMEMORY;
713 omapi_connection_copyout
714 (p -> message -> authenticator -> u.buffer.value, c,
715 p -> message -> authlen);
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;
728 if (signature != NULL) {
729 omapi_value_dereference (&signature, MDL);
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);
742 if (status != ISC_R_SUCCESS) {
743 omapi_disconnect (c, 1);
744 return ISC_R_NOMEMORY;
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;
766 default:
767 /* XXX should never get here. Assertion? */
768 break;
770 return ISC_R_SUCCESS;
773 isc_result_t omapi_protocol_add_auth (omapi_object_t *po,
774 omapi_object_t *ao,
775 omapi_handle_t handle)
777 omapi_protocol_object_t *p;
778 omapi_remote_auth_t *r;
779 isc_result_t status;
781 if (ao -> type != omapi_type_auth_key &&
782 (!ao -> inner || ao -> inner -> type != omapi_type_auth_key))
783 return DHCP_R_INVALIDARG;
785 if (po -> type != omapi_type_protocol)
786 return DHCP_R_INVALIDARG;
787 p = (omapi_protocol_object_t *)po;
789 #ifdef DEBUG_PROTOCOL
790 log_debug ("omapi_protocol_add_auth(name=%s)",
791 ((omapi_auth_key_t *)ao) -> name);
792 #endif
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;
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;
810 p -> remote_auth_list = p -> default_auth;
811 p -> default_auth -> remote_handle = handle;
813 return omapi_signal_in (p -> inner, "ready");
816 r = dmalloc (sizeof(*r), MDL);
817 if (!r)
818 return ISC_R_NOMEMORY;
820 status = omapi_object_reference (&r -> a, ao, MDL);
821 if (status != ISC_R_SUCCESS) {
822 dfree (r, MDL);
823 return status;
826 r -> remote_handle = handle;
827 r -> next = p -> remote_auth_list;
828 p -> remote_auth_list = r;
830 return ISC_R_SUCCESS;
833 isc_result_t omapi_protocol_lookup_auth (omapi_object_t **a,
834 omapi_object_t *po,
835 omapi_handle_t handle)
837 omapi_protocol_object_t *p;
838 omapi_remote_auth_t *r;
840 if (po -> type != omapi_type_protocol)
841 return DHCP_R_INVALIDARG;
842 p = (omapi_protocol_object_t *)po;
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);
848 return DHCP_R_KEY_UNKNOWN;
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)
856 omapi_protocol_object_t *p;
857 omapi_remote_auth_t *r;
859 if (h -> type != omapi_type_protocol)
860 return DHCP_R_INVALIDARG;
861 p = (omapi_protocol_object_t *)h;
863 if (omapi_ds_strcmp (name, "default-authenticator") == 0) {
864 if (!value || value -> type != omapi_datatype_object)
865 return DHCP_R_INVALIDARG;
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;
874 if (!r)
875 return DHCP_R_KEY_UNKNOWN;
877 p -> default_auth = r;
880 return ISC_R_SUCCESS;
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;
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)
894 omapi_protocol_object_t *p;
896 if (h -> type != omapi_type_protocol)
897 return DHCP_R_INVALIDARG;
898 p = (omapi_protocol_object_t *)h;
900 if (omapi_ds_strcmp (name, "default-authenticator") == 0) {
901 if (!p -> default_auth)
902 return ISC_R_NOTFOUND;
904 return omapi_make_object_value (value, name,
905 p -> default_auth -> a, MDL);
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;
914 isc_result_t omapi_protocol_destroy (omapi_object_t *h,
915 const char *file, int line)
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);
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);
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);
936 return ISC_R_SUCCESS;
939 /* Write all the published values associated with the object through the
940 specified connection. */
942 isc_result_t omapi_protocol_stuff_values (omapi_object_t *c,
943 omapi_object_t *id,
944 omapi_object_t *p)
946 if (p -> type != omapi_type_protocol)
947 return DHCP_R_INVALIDARG;
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;
955 /* Returns a boolean indicating whether this protocol requires that
956 messages be authenticated or not. */
958 isc_boolean_t omapi_protocol_authenticated (omapi_object_t *h)
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;
968 /* Sets the address and authenticator verification callbacks. The handle
969 is to a listener object, not a protocol object. */
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 *))
979 omapi_protocol_listener_object_t *l;
981 if (h -> outer && h -> outer -> type == omapi_type_protocol_listener)
982 h = h -> outer;
984 if (h -> type != omapi_type_protocol_listener)
985 return DHCP_R_INVALIDARG;
986 l = (omapi_protocol_listener_object_t *)h;
988 l -> verify_auth = verify_auth;
989 l -> insecure = 0;
991 if (h -> outer != NULL) {
992 return omapi_listener_configure_security (h -> outer, verify_addr);
993 } else {
994 return DHCP_R_INVALIDARG;
999 /* Set up a listener for the omapi protocol. The handle stored points to
1000 a listener object, not a protocol object. */
1002 isc_result_t omapi_protocol_listen (omapi_object_t *h,
1003 unsigned port,
1004 int max)
1006 isc_result_t status;
1007 omapi_protocol_listener_object_t *obj;
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;
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;
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;
1026 /* What a terrible default. */
1027 obj -> insecure = 1;
1029 status = omapi_listen ((omapi_object_t *)obj, port, max);
1030 omapi_protocol_listener_dereference (&obj, MDL);
1031 return status;
1034 /* Signal handler for protocol listener - if we get a connect signal,
1035 create a new protocol connection, otherwise pass the signal down. */
1037 isc_result_t omapi_protocol_listener_signal (omapi_object_t *o,
1038 const char *name, va_list ap)
1040 isc_result_t status;
1041 omapi_object_t *c;
1042 omapi_protocol_object_t *obj;
1043 omapi_protocol_listener_object_t *p;
1045 if (!o || o -> type != omapi_type_protocol_listener)
1046 return DHCP_R_INVALIDARG;
1047 p = (omapi_protocol_listener_object_t *)o;
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;
1057 c = va_arg (ap, omapi_object_t *);
1058 if (!c || c -> type != omapi_type_connection)
1059 return DHCP_R_INVALIDARG;
1061 obj = (omapi_protocol_object_t *)0;
1062 status = omapi_protocol_allocate (&obj, MDL);
1063 if (status != ISC_R_SUCCESS)
1064 return status;
1066 obj -> verify_auth = p -> verify_auth;
1067 obj -> insecure = p -> insecure;
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;
1077 status = omapi_object_reference (&c -> inner,
1078 (omapi_object_t *)obj, MDL);
1079 if (status != ISC_R_SUCCESS)
1080 goto lose;
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;
1089 omapi_protocol_dereference (&obj, MDL);
1090 return status;
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)
1098 if (h -> type != omapi_type_protocol_listener)
1099 return DHCP_R_INVALIDARG;
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;
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)
1112 if (h -> type != omapi_type_protocol_listener)
1113 return DHCP_R_INVALIDARG;
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;
1121 isc_result_t omapi_protocol_listener_destroy (omapi_object_t *h,
1122 const char *file, int line)
1124 if (h -> type != omapi_type_protocol_listener)
1125 return DHCP_R_INVALIDARG;
1126 return ISC_R_SUCCESS;
1129 /* Write all the published values associated with the object through the
1130 specified connection. */
1132 isc_result_t omapi_protocol_listener_stuff (omapi_object_t *c,
1133 omapi_object_t *id,
1134 omapi_object_t *p)
1136 if (p -> type != omapi_type_protocol_listener)
1137 return DHCP_R_INVALIDARG;
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;
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)
1150 isc_result_t status;
1151 omapi_message_object_t *message = (omapi_message_object_t *)0;
1152 omapi_object_t *mo;
1154 if (po -> type != omapi_type_protocol)
1155 return DHCP_R_INVALIDARG;
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;
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;
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;
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;
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;
1193 status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0);
1194 omapi_message_dereference (&message, MDL);
1195 return status;
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. */
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)
1208 isc_result_t status;
1209 omapi_message_object_t *message = (omapi_message_object_t *)0;
1210 omapi_object_t *mo;
1212 if (po -> type != omapi_type_protocol)
1213 return DHCP_R_INVALIDARG;
1215 status = omapi_message_new ((omapi_object_t **)&message, MDL);
1216 mo = (omapi_object_t *)message;
1218 if (status == ISC_R_SUCCESS)
1219 status = omapi_set_int_value (mo, (omapi_object_t *)0,
1220 "op", OMAPI_OP_OPEN);
1222 if (status == ISC_R_SUCCESS)
1223 status = omapi_set_object_value (mo, (omapi_object_t *)0,
1224 "object", object);
1226 if ((flags & OMAPI_CREATE) && (status == ISC_R_SUCCESS))
1227 status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1228 "create", 1);
1230 if ((flags & OMAPI_UPDATE) && (status == ISC_R_SUCCESS))
1231 status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1232 "update", 1);
1234 if ((flags & OMAPI_EXCL) && (status == ISC_R_SUCCESS))
1235 status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1236 "exclusive", 1);
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);
1242 if (type && (status == ISC_R_SUCCESS))
1243 status = omapi_set_string_value (mo, (omapi_object_t *)0,
1244 "type", type);
1246 if (status == ISC_R_SUCCESS)
1247 status = omapi_message_register (mo);
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);
1256 if (message)
1257 omapi_message_dereference (&message, MDL);
1259 return status;
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)
1267 isc_result_t status;
1268 omapi_message_object_t *message = (omapi_message_object_t *)0;
1269 omapi_object_t *mo;
1271 if (po -> type != omapi_type_protocol)
1272 return DHCP_R_INVALIDARG;
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;
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;
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;
1295 status = omapi_object_handle (&handle, object);
1296 if (status != ISC_R_SUCCESS) {
1297 omapi_message_dereference (&message, MDL);
1298 return status;
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;
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;
1315 status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0);
1316 omapi_message_dereference (&message, MDL);
1317 return status;