]> git.ipfire.org Git - thirdparty/dhcp.git/blob - omapip/protocol.c
- Silence benign static analysis warnings.
[thirdparty/dhcp.git] / omapip / protocol.c
1 /* protocol.c
2
3 Functions supporting the object management protocol... */
4
5 /*
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
9 *
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.
13 *
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.
21 *
22 * Internet Systems Consortium, Inc.
23 * 950 Charter Street
24 * Redwood City, CA 94063
25 * <info@isc.org>
26 * https://www.isc.org/
27 *
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''.
34 */
35
36 #include "dhcpd.h"
37
38 #include <omapip/omapip_p.h>
39
40 OMAPI_OBJECT_ALLOC (omapi_protocol, omapi_protocol_object_t,
41 omapi_type_protocol)
42 OMAPI_OBJECT_ALLOC (omapi_protocol_listener, omapi_protocol_listener_object_t,
43 omapi_type_protocol_listener)
44
45 isc_result_t omapi_protocol_connect (omapi_object_t *h,
46 const char *server_name,
47 unsigned port,
48 omapi_object_t *a)
49 {
50 isc_result_t rstatus, status;
51 omapi_protocol_object_t *obj;
52
53 #ifdef DEBUG_PROTOCOL
54 log_debug ("omapi_protocol_connect(%s port=%d)", server_name, port);
55 #endif
56
57 obj = (omapi_protocol_object_t *)0;
58 status = omapi_protocol_allocate (&obj, MDL);
59 if (status != ISC_R_SUCCESS)
60 return status;
61
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);
65 return rstatus;
66 }
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);
71 return status;
72 }
73 status = omapi_object_reference (&obj -> inner, h, MDL);
74 if (status != ISC_R_SUCCESS) {
75 omapi_protocol_dereference (&obj, MDL);
76 return status;
77 }
78
79 /* If we were passed a default authenticator, store it now. We'll
80 open it once we're connected. */
81 if (a) {
82 obj -> default_auth =
83 dmalloc (sizeof(omapi_remote_auth_t), MDL);
84 if (!obj -> default_auth) {
85 omapi_protocol_dereference (&obj, MDL);
86 return ISC_R_NOMEMORY;
87 }
88
89 obj -> default_auth -> next = (omapi_remote_auth_t *)0;
90 status = omapi_object_reference (&obj -> default_auth -> a,
91 a, MDL);
92 if (status != ISC_R_SUCCESS) {
93 dfree (obj -> default_auth, MDL);
94 omapi_protocol_dereference (&obj, MDL);
95 return status;
96 }
97
98 obj -> insecure = 0;
99 rstatus = DHCP_R_INCOMPLETE;
100 } else {
101 obj -> insecure = 1;
102 #if 0
103 status = ISC_R_SUCCESS;
104 #endif
105 }
106
107 omapi_protocol_dereference (&obj, MDL);
108 return rstatus;
109 }
110
111 /* Send the protocol introduction message. */
112 isc_result_t omapi_protocol_send_intro (omapi_object_t *h,
113 unsigned ver,
114 unsigned hsize)
115 {
116 isc_result_t status;
117 omapi_protocol_object_t *p;
118
119 #ifdef DEBUG_PROTOCOL
120 log_debug ("omapi_protocol_send_intro()");
121 #endif
122
123 if (h -> type != omapi_type_protocol)
124 return DHCP_R_INVALIDARG;
125 p = (omapi_protocol_object_t *)h;
126
127 if (!h -> outer || h -> outer -> type != omapi_type_connection)
128 return ISC_R_NOTCONNECTED;
129
130 status = omapi_connection_put_uint32 (h -> outer, ver);
131 if (status != ISC_R_SUCCESS)
132 return status;
133
134 status = omapi_connection_put_uint32 (h -> outer, hsize);
135
136 if (status != ISC_R_SUCCESS)
137 return status;
138
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)
144 return status;
145
146 /* Make up an initial transaction ID for this connection. */
147 p -> next_xid = random ();
148 return ISC_R_SUCCESS;
149 }
150
151 #ifdef DEBUG_PROTOCOL
152 extern const char *omapi_message_op_name(int);
153 #endif /* DEBUG_PROTOCOL */
154
155 isc_result_t omapi_protocol_send_message (omapi_object_t *po,
156 omapi_object_t *id,
157 omapi_object_t *mo,
158 omapi_object_t *omo)
159 {
160 omapi_protocol_object_t *p;
161 omapi_object_t *c;
162 omapi_message_object_t *m, *om;
163 omapi_remote_auth_t *ra;
164 omapi_value_t *signature;
165 isc_result_t status;
166 unsigned auth_len;
167
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;
178
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);
185 #endif
186
187 /* Find the authid to use for this message. */
188 if (id) {
189 for (ra = p -> remote_auth_list; ra; ra = ra -> next) {
190 if (ra -> a == id) {
191 break;
192 }
193 }
194
195 if (!ra)
196 return DHCP_R_KEY_UNKNOWN;
197 } else if (p -> remote_auth_list) {
198 ra = p -> default_auth;
199 } else {
200 ra = (omapi_remote_auth_t *)0;
201 }
202
203 if (ra) {
204 m -> authid = ra -> remote_handle;
205 status = omapi_object_reference (&m -> id_object,
206 ra -> a, MDL);
207 if (status != ISC_R_SUCCESS)
208 return status;
209 }
210
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);
215 return status;
216 }
217
218 /* Activate the authentication key on the connection. */
219 auth_len = 0;
220 if (ra) {
221 status = omapi_set_object_value (c, (omapi_object_t *)0,
222 "output-authenticator",
223 ra -> a);
224 if (status != ISC_R_SUCCESS) {
225 omapi_disconnect (c, 1);
226 return status;
227 }
228
229 status = omapi_connection_output_auth_length (c, &auth_len);
230 if (status != ISC_R_SUCCESS) {
231 omapi_disconnect (c, 1);
232 return status;
233 }
234 }
235
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);
240 return status;
241 }
242
243 /* Write the opcode. */
244 status = omapi_connection_put_uint32 (c, m -> op);
245 if (status != ISC_R_SUCCESS) {
246 omapi_disconnect (c, 1);
247 return status;
248 }
249
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
255 ? m -> h
256 : (m -> object
257 ? m -> object -> handle
258 : 0)));
259 if (status != ISC_R_SUCCESS) {
260 omapi_disconnect (c, 1);
261 return status;
262 }
263
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);
269 return status;
270 }
271
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);
277 return status;
278 }
279
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);
284 return status;
285 }
286
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);
292 return status;
293 }
294
295 /* Stuff out all the published name/value pairs in the object that's
296 being sent in the message, if there is one. */
297 if (m -> object) {
298 status = omapi_stuff_values (c, id, m -> object);
299 if (status != ISC_R_SUCCESS) {
300 omapi_disconnect (c, 1);
301 return status;
302 }
303 }
304
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);
310 return status;
311 }
312
313 if (ra) {
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);
320 return status;
321 }
322
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);
330 return status;
331 }
332
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);
339 return status;
340 }
341 }
342
343 if (!omo) {
344 omapi_protocol_reference (&m -> protocol_object, p, MDL);
345 }
346 return ISC_R_SUCCESS;
347 }
348
349
350 isc_result_t omapi_protocol_signal_handler (omapi_object_t *h,
351 const char *name, va_list ap)
352 {
353 isc_result_t status;
354 omapi_protocol_object_t *p;
355 omapi_object_t *c;
356 omapi_message_object_t *m;
357 omapi_value_t *signature = NULL;
358 u_int16_t nlen;
359 u_int32_t vlen;
360 u_int32_t th;
361 #if defined (DEBUG_MEMORY_LEAKAGE)
362 unsigned long previous_outstanding = 0xDEADBEEF;
363 unsigned long connect_outstanding = 0xDEADBEEF;
364 #endif
365
366 if (h -> type != omapi_type_protocol) {
367 /* XXX shouldn't happen. Put an assert here? */
368 return ISC_R_UNEXPECTED;
369 }
370 p = (omapi_protocol_object_t *)h;
371
372 if (!strcmp (name, "connect")) {
373 #if defined (DEBUG_MEMORY_LEAKAGE)
374 connect_outstanding = dmalloc_outstanding;
375 #endif
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);
382 return status;
383 }
384 return ISC_R_SUCCESS;
385 }
386
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);
394 return status;
395 } else {
396 return omapi_signal_in (h -> inner, "ready");
397 }
398 }
399
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",
405 dmalloc_generation,
406 dmalloc_outstanding - previous_outstanding,
407 dmalloc_outstanding, dmalloc_longterm, " long-term");
408 }
409 #endif
410 #if defined (DEBUG_MEMORY_LEAKAGE)
411 dmalloc_dump_outstanding ();
412 #endif
413 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
414 dump_rc_history (h);
415 #endif
416 for (m = omapi_registered_messages; m; m = m -> next) {
417 if (m -> protocol_object == p) {
418 if (m -> object)
419 omapi_signal (m -> object, "disconnect");
420 }
421 }
422
423 /* XXX */
424 return ISC_R_SUCCESS;
425 }
426
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,
431 name,
432 ap);
433 return ISC_R_NOTFOUND;
434 }
435
436 if (!p -> outer || p -> outer -> type != omapi_type_connection)
437 return DHCP_R_INVALIDARG;
438 c = p -> outer;
439
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
446 byte order. */
447 omapi_connection_get_uint32 (c, &p -> protocol_version);
448 omapi_connection_get_uint32 (c, &p -> header_size);
449
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;
454 }
455
456 if (p -> header_size < sizeof (omapi_protocol_header_t)) {
457 omapi_disconnect (c, 1);
458 return DHCP_R_PROTOCOLERROR;
459 }
460
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);
468 return status;
469 }
470 } else {
471 status = omapi_signal_in (h -> inner, "ready");
472 }
473
474 to_header_wait:
475 /* The next thing we're expecting is a message header. */
476 p -> state = omapi_protocol_header_wait;
477
478 /* Register a need for the number of bytes in a
479 header, and if we already have that many, process
480 them immediately. */
481 if ((omapi_connection_require (c, p -> header_size)) !=
482 ISC_R_SUCCESS)
483 break;
484 /* If we already have the data, fall through. */
485
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,
493 " long-term");
494 #endif
495 #if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
496 dmalloc_dump_outstanding ();
497 #endif
498 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
499 dump_rc_history (h);
500 #endif
501 #if defined (DEBUG_MEMORY_LEAKAGE)
502 }
503 previous_outstanding = dmalloc_outstanding;
504 #endif
505 status = omapi_message_new ((omapi_object_t **)&p -> message,
506 MDL);
507 if (status != ISC_R_SUCCESS) {
508 omapi_disconnect (c, 1);
509 return status;
510 }
511
512 p -> verify_result = ISC_R_SUCCESS;
513
514 /* Swap in the header... */
515 omapi_connection_get_uint32 (c, &p -> message -> authid);
516
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;
524
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);
531 return status;
532 }
533 }
534
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);
541
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)));
547 }
548
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. */
553
554 /* First we read in message-specific values, then object
555 values. */
556 p -> reading_message_values = 1;
557
558 need_name_length:
559 /* The next thing we're expecting is length of the
560 first name. */
561 p -> state = omapi_protocol_name_length_wait;
562
563 /* Wait for a 16-bit length. */
564 if ((omapi_connection_require (c, 2)) != ISC_R_SUCCESS)
565 break;
566 /* If it's already here, fall through. */
567
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
571 pairs. */
572 if (nlen == 0) {
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
577 object. */
578 if (p -> reading_message_values) {
579 p -> reading_message_values = 0;
580 goto need_name_length;
581 }
582
583 /* If the authenticator length is zero, there's no
584 signature to read in, so go straight to processing
585 the message. */
586 if (p -> message -> authlen == 0)
587 goto message_done;
588
589 /* The next thing we're expecting is the
590 message signature. */
591 p -> state = omapi_protocol_signature_wait;
592
593 /* Wait for the number of bytes specified for
594 the authenticator. If we already have it,
595 go read it in. */
596 if (omapi_connection_require
597 (c, p -> message -> authlen) == ISC_R_SUCCESS)
598 goto signature_wait;
599 break;
600 }
601
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;
607 }
608 p -> state = omapi_protocol_name_wait;
609 if (omapi_connection_require (c, nlen) != ISC_R_SUCCESS)
610 break;
611 /* If it's already here, fall through. */
612
613 case omapi_protocol_name_wait:
614 omapi_connection_copyout (p -> name -> value, c,
615 p -> name -> len);
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)
619 break;
620 /* If it's already here, fall through. */
621
622 case omapi_protocol_value_length_wait:
623 omapi_connection_get_uint32 (c, &vlen);
624
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. */
628 if (!vlen)
629 goto insert_new_value;
630
631 status = omapi_typed_data_new (MDL, &p -> value,
632 omapi_datatype_data,
633 vlen);
634 if (status != ISC_R_SUCCESS) {
635 omapi_disconnect (c, 1);
636 return ISC_R_NOMEMORY;
637 }
638
639 p -> state = omapi_protocol_value_wait;
640 if (omapi_connection_require (c, vlen) != ISC_R_SUCCESS)
641 break;
642 /* If it's already here, fall through. */
643
644 case omapi_protocol_value_wait:
645 omapi_connection_copyout (p -> value -> u.buffer.value, c,
646 p -> value -> u.buffer.len);
647
648 insert_new_value:
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));
654 } else {
655 if (!p -> message -> object) {
656 /* We need a generic object to hang off of the
657 incoming message. */
658 status = (omapi_generic_new
659 (&p -> message -> object, MDL));
660 if (status != ISC_R_SUCCESS) {
661 omapi_disconnect (c, 1);
662 return status;
663 }
664 }
665 status = (omapi_set_value
666 ((omapi_object_t *)p -> message -> object,
667 p -> message -> id_object,
668 p -> name, p -> value));
669 }
670 if (status != ISC_R_SUCCESS) {
671 omapi_disconnect (c, 1);
672 return status;
673 }
674 omapi_data_string_dereference (&p -> name, MDL);
675 if (p -> value)
676 omapi_typed_data_dereference (&p -> value, MDL);
677 goto need_name_length;
678
679 signature_wait:
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,
684 "input-signature",
685 &signature);
686 if (status != ISC_R_SUCCESS) {
687 omapi_disconnect (c, 1);
688 return status;
689 }
690
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);
698 return status;
699 }
700 }
701
702 /* Read the authenticator. */
703 status = omapi_typed_data_new (MDL,
704 &p -> message -> authenticator,
705 omapi_datatype_data,
706 p -> message -> authlen);
707
708 if (status != ISC_R_SUCCESS) {
709 if (signature != NULL) {
710 omapi_value_dereference (&signature, MDL);
711 }
712 omapi_disconnect (c, 1);
713 return ISC_R_NOMEMORY;
714 }
715 omapi_connection_copyout
716 (p -> message -> authenticator -> u.buffer.value, c,
717 p -> message -> authlen);
718
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;
728 }
729
730 if (signature != NULL) {
731 omapi_value_dereference (&signature, MDL);
732 }
733
734 /* Process the message. */
735 message_done:
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);
740 } else {
741 status = omapi_message_process
742 ((omapi_object_t *)p -> message, h);
743 }
744 if (status != ISC_R_SUCCESS) {
745 omapi_disconnect (c, 1);
746 return ISC_R_NOMEMORY;
747 }
748
749 omapi_message_dereference (&p -> message, MDL);
750 #if defined (DEBUG_MEMORY_LEAKAGE)
751 log_info ("generation %ld: %ld new, %ld outstanding, %ld%s",
752 dmalloc_generation,
753 dmalloc_outstanding - previous_outstanding,
754 dmalloc_outstanding, dmalloc_longterm, " long-term");
755 #endif
756 #if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
757 dmalloc_dump_outstanding ();
758 #endif
759 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
760 dump_rc_history (h);
761 #endif
762 #if defined (DEBUG_MEMORY_LEAKAGE)
763 previous_outstanding = 0xDEADBEEF;
764 #endif
765 /* Now wait for the next message. */
766 goto to_header_wait;
767
768 default:
769 /* XXX should never get here. Assertion? */
770 break;
771 }
772 return ISC_R_SUCCESS;
773 }
774
775 isc_result_t omapi_protocol_add_auth (omapi_object_t *po,
776 omapi_object_t *ao,
777 omapi_handle_t handle)
778 {
779 omapi_protocol_object_t *p;
780 omapi_remote_auth_t *r;
781 isc_result_t status;
782
783 if (ao -> type != omapi_type_auth_key &&
784 (!ao -> inner || ao -> inner -> type != omapi_type_auth_key))
785 return DHCP_R_INVALIDARG;
786
787 if (po -> type != omapi_type_protocol)
788 return DHCP_R_INVALIDARG;
789 p = (omapi_protocol_object_t *)po;
790
791 #ifdef DEBUG_PROTOCOL
792 log_debug ("omapi_protocol_add_auth(name=%s)",
793 ((omapi_auth_key_t *)ao) -> name);
794 #endif
795
796 if (p -> verify_auth) {
797 status = (p -> verify_auth) (po, (omapi_auth_key_t *)ao);
798 if (status != ISC_R_SUCCESS)
799 return status;
800 }
801
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;
810 }
811
812 p -> remote_auth_list = p -> default_auth;
813 p -> default_auth -> remote_handle = handle;
814
815 return omapi_signal_in (p -> inner, "ready");
816 }
817
818 r = dmalloc (sizeof(*r), MDL);
819 if (!r)
820 return ISC_R_NOMEMORY;
821
822 status = omapi_object_reference (&r -> a, ao, MDL);
823 if (status != ISC_R_SUCCESS) {
824 dfree (r, MDL);
825 return status;
826 }
827
828 r -> remote_handle = handle;
829 r -> next = p -> remote_auth_list;
830 p -> remote_auth_list = r;
831
832 return ISC_R_SUCCESS;
833 }
834
835 isc_result_t omapi_protocol_lookup_auth (omapi_object_t **a,
836 omapi_object_t *po,
837 omapi_handle_t handle)
838 {
839 omapi_protocol_object_t *p;
840 omapi_remote_auth_t *r;
841
842 if (po -> type != omapi_type_protocol)
843 return DHCP_R_INVALIDARG;
844 p = (omapi_protocol_object_t *)po;
845
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);
849
850 return DHCP_R_KEY_UNKNOWN;
851 }
852
853 isc_result_t omapi_protocol_set_value (omapi_object_t *h,
854 omapi_object_t *id,
855 omapi_data_string_t *name,
856 omapi_typed_data_t *value)
857 {
858 omapi_protocol_object_t *p;
859 omapi_remote_auth_t *r;
860
861 if (h -> type != omapi_type_protocol)
862 return DHCP_R_INVALIDARG;
863 p = (omapi_protocol_object_t *)h;
864
865 if (omapi_ds_strcmp (name, "default-authenticator") == 0) {
866 if (!value || value -> type != omapi_datatype_object)
867 return DHCP_R_INVALIDARG;
868
869 if (!value -> u.object) {
870 p -> default_auth = (omapi_remote_auth_t *)0;
871 } else {
872 for (r = p -> remote_auth_list; r; r = r -> next)
873 if (r -> a == value -> u.object)
874 break;
875
876 if (!r)
877 return DHCP_R_KEY_UNKNOWN;
878
879 p -> default_auth = r;
880 }
881
882 return ISC_R_SUCCESS;
883 }
884
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;
889 }
890
891 isc_result_t omapi_protocol_get_value (omapi_object_t *h,
892 omapi_object_t *id,
893 omapi_data_string_t *name,
894 omapi_value_t **value)
895 {
896 omapi_protocol_object_t *p;
897
898 if (h -> type != omapi_type_protocol)
899 return DHCP_R_INVALIDARG;
900 p = (omapi_protocol_object_t *)h;
901
902 if (omapi_ds_strcmp (name, "default-authenticator") == 0) {
903 if (!p -> default_auth)
904 return ISC_R_NOTFOUND;
905
906 return omapi_make_object_value (value, name,
907 p -> default_auth -> a, MDL);
908 }
909
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;
914 }
915
916 isc_result_t omapi_protocol_destroy (omapi_object_t *h,
917 const char *file, int line)
918 {
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;
923 if (p -> message)
924 omapi_message_dereference (&p -> message, file, line);
925
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);
931
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);
937 }
938 return ISC_R_SUCCESS;
939 }
940
941 /* Write all the published values associated with the object through the
942 specified connection. */
943
944 isc_result_t omapi_protocol_stuff_values (omapi_object_t *c,
945 omapi_object_t *id,
946 omapi_object_t *p)
947 {
948 if (p -> type != omapi_type_protocol)
949 return DHCP_R_INVALIDARG;
950
951 if (p -> inner && p -> inner -> type -> stuff_values)
952 return (*(p -> inner -> type -> stuff_values)) (c, id,
953 p -> inner);
954 return ISC_R_SUCCESS;
955 }
956
957 /* Returns a boolean indicating whether this protocol requires that
958 messages be authenticated or not. */
959
960 isc_boolean_t omapi_protocol_authenticated (omapi_object_t *h)
961 {
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;
966 else
967 return isc_boolean_true;
968 }
969
970 /* Sets the address and authenticator verification callbacks. The handle
971 is to a listener object, not a protocol object. */
972
973 isc_result_t omapi_protocol_configure_security (omapi_object_t *h,
974 isc_result_t (*verify_addr)
975 (omapi_object_t *,
976 omapi_addr_t *),
977 isc_result_t (*verify_auth)
978 (omapi_object_t *,
979 omapi_auth_key_t *))
980 {
981 omapi_protocol_listener_object_t *l;
982
983 if (h -> outer && h -> outer -> type == omapi_type_protocol_listener)
984 h = h -> outer;
985
986 if (h -> type != omapi_type_protocol_listener)
987 return DHCP_R_INVALIDARG;
988 l = (omapi_protocol_listener_object_t *)h;
989
990 l -> verify_auth = verify_auth;
991 l -> insecure = 0;
992
993 if (h -> outer != NULL) {
994 return omapi_listener_configure_security (h -> outer, verify_addr);
995 } else {
996 return DHCP_R_INVALIDARG;
997 }
998 }
999
1000
1001 /* Set up a listener for the omapi protocol. The handle stored points to
1002 a listener object, not a protocol object. */
1003
1004 isc_result_t omapi_protocol_listen (omapi_object_t *h,
1005 unsigned port,
1006 int max)
1007 {
1008 isc_result_t status;
1009 omapi_protocol_listener_object_t *obj;
1010
1011 obj = (omapi_protocol_listener_object_t *)0;
1012 status = omapi_protocol_listener_allocate (&obj, MDL);
1013 if (status != ISC_R_SUCCESS)
1014 return status;
1015
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);
1020 return status;
1021 }
1022 status = omapi_object_reference (&obj -> inner, h, MDL);
1023 if (status != ISC_R_SUCCESS) {
1024 omapi_protocol_listener_dereference (&obj, MDL);
1025 return status;
1026 }
1027
1028 /* What a terrible default. */
1029 obj -> insecure = 1;
1030
1031 status = omapi_listen ((omapi_object_t *)obj, port, max);
1032 omapi_protocol_listener_dereference (&obj, MDL);
1033 return status;
1034 }
1035
1036 /* Signal handler for protocol listener - if we get a connect signal,
1037 create a new protocol connection, otherwise pass the signal down. */
1038
1039 isc_result_t omapi_protocol_listener_signal (omapi_object_t *o,
1040 const char *name, va_list ap)
1041 {
1042 isc_result_t status;
1043 omapi_object_t *c;
1044 omapi_protocol_object_t *obj;
1045 omapi_protocol_listener_object_t *p;
1046
1047 if (!o || o -> type != omapi_type_protocol_listener)
1048 return DHCP_R_INVALIDARG;
1049 p = (omapi_protocol_listener_object_t *)o;
1050
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;
1057 }
1058
1059 c = va_arg (ap, omapi_object_t *);
1060 if (!c || c -> type != omapi_type_connection)
1061 return DHCP_R_INVALIDARG;
1062
1063 obj = (omapi_protocol_object_t *)0;
1064 status = omapi_protocol_allocate (&obj, MDL);
1065 if (status != ISC_R_SUCCESS)
1066 return status;
1067
1068 obj -> verify_auth = p -> verify_auth;
1069 obj -> insecure = p -> insecure;
1070
1071 status = omapi_object_reference (&obj -> outer, c, MDL);
1072 if (status != ISC_R_SUCCESS) {
1073 lose:
1074 omapi_protocol_dereference (&obj, MDL);
1075 omapi_disconnect (c, 1);
1076 return status;
1077 }
1078
1079 status = omapi_object_reference (&c -> inner,
1080 (omapi_object_t *)obj, MDL);
1081 if (status != ISC_R_SUCCESS)
1082 goto lose;
1083
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)
1089 goto lose;
1090
1091 omapi_protocol_dereference (&obj, MDL);
1092 return status;
1093 }
1094
1095 isc_result_t omapi_protocol_listener_set_value (omapi_object_t *h,
1096 omapi_object_t *id,
1097 omapi_data_string_t *name,
1098 omapi_typed_data_t *value)
1099 {
1100 if (h -> type != omapi_type_protocol_listener)
1101 return DHCP_R_INVALIDARG;
1102
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;
1107 }
1108
1109 isc_result_t omapi_protocol_listener_get_value (omapi_object_t *h,
1110 omapi_object_t *id,
1111 omapi_data_string_t *name,
1112 omapi_value_t **value)
1113 {
1114 if (h -> type != omapi_type_protocol_listener)
1115 return DHCP_R_INVALIDARG;
1116
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;
1121 }
1122
1123 isc_result_t omapi_protocol_listener_destroy (omapi_object_t *h,
1124 const char *file, int line)
1125 {
1126 if (h -> type != omapi_type_protocol_listener)
1127 return DHCP_R_INVALIDARG;
1128 return ISC_R_SUCCESS;
1129 }
1130
1131 /* Write all the published values associated with the object through the
1132 specified connection. */
1133
1134 isc_result_t omapi_protocol_listener_stuff (omapi_object_t *c,
1135 omapi_object_t *id,
1136 omapi_object_t *p)
1137 {
1138 if (p -> type != omapi_type_protocol_listener)
1139 return DHCP_R_INVALIDARG;
1140
1141 if (p -> inner && p -> inner -> type -> stuff_values)
1142 return (*(p -> inner -> type -> stuff_values)) (c, id,
1143 p -> inner);
1144 return ISC_R_SUCCESS;
1145 }
1146
1147 isc_result_t omapi_protocol_send_status (omapi_object_t *po,
1148 omapi_object_t *id,
1149 isc_result_t waitstatus,
1150 unsigned rid, const char *msg)
1151 {
1152 isc_result_t status;
1153 omapi_message_object_t *message = (omapi_message_object_t *)0;
1154 omapi_object_t *mo;
1155
1156 if (po -> type != omapi_type_protocol)
1157 return DHCP_R_INVALIDARG;
1158
1159 status = omapi_message_new ((omapi_object_t **)&message, MDL);
1160 if (status != ISC_R_SUCCESS)
1161 return status;
1162 mo = (omapi_object_t *)message;
1163
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);
1168 return status;
1169 }
1170
1171 status = omapi_set_int_value (mo, (omapi_object_t *)0,
1172 "rid", (int)rid);
1173 if (status != ISC_R_SUCCESS) {
1174 omapi_message_dereference (&message, MDL);
1175 return status;
1176 }
1177
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);
1182 return status;
1183 }
1184
1185 /* If a message has been provided, send it. */
1186 if (msg) {
1187 status = omapi_set_string_value (mo, (omapi_object_t *)0,
1188 "message", msg);
1189 if (status != ISC_R_SUCCESS) {
1190 omapi_message_dereference (&message, MDL);
1191 return status;
1192 }
1193 }
1194
1195 status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0);
1196 omapi_message_dereference (&message, MDL);
1197 return status;
1198 }
1199
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. */
1203
1204 isc_result_t omapi_protocol_send_open (omapi_object_t *po,
1205 omapi_object_t *id,
1206 const char *type,
1207 omapi_object_t *object,
1208 unsigned flags)
1209 {
1210 isc_result_t status;
1211 omapi_message_object_t *message = (omapi_message_object_t *)0;
1212 omapi_object_t *mo;
1213
1214 if (po -> type != omapi_type_protocol)
1215 return DHCP_R_INVALIDARG;
1216
1217 status = omapi_message_new ((omapi_object_t **)&message, MDL);
1218 mo = (omapi_object_t *)message;
1219
1220 if (status == ISC_R_SUCCESS)
1221 status = omapi_set_int_value (mo, (omapi_object_t *)0,
1222 "op", OMAPI_OP_OPEN);
1223
1224 if (status == ISC_R_SUCCESS)
1225 status = omapi_set_object_value (mo, (omapi_object_t *)0,
1226 "object", object);
1227
1228 if ((flags & OMAPI_CREATE) && (status == ISC_R_SUCCESS))
1229 status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1230 "create", 1);
1231
1232 if ((flags & OMAPI_UPDATE) && (status == ISC_R_SUCCESS))
1233 status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1234 "update", 1);
1235
1236 if ((flags & OMAPI_EXCL) && (status == ISC_R_SUCCESS))
1237 status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1238 "exclusive", 1);
1239
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);
1243
1244 if (type && (status == ISC_R_SUCCESS))
1245 status = omapi_set_string_value (mo, (omapi_object_t *)0,
1246 "type", type);
1247
1248 if (status == ISC_R_SUCCESS)
1249 status = omapi_message_register (mo);
1250
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);
1256 }
1257
1258 if (message)
1259 omapi_message_dereference (&message, MDL);
1260
1261 return status;
1262 }
1263
1264 isc_result_t omapi_protocol_send_update (omapi_object_t *po,
1265 omapi_object_t *id,
1266 unsigned rid,
1267 omapi_object_t *object)
1268 {
1269 isc_result_t status;
1270 omapi_message_object_t *message = (omapi_message_object_t *)0;
1271 omapi_object_t *mo;
1272
1273 if (po -> type != omapi_type_protocol)
1274 return DHCP_R_INVALIDARG;
1275
1276 status = omapi_message_new ((omapi_object_t **)&message, MDL);
1277 if (status != ISC_R_SUCCESS)
1278 return status;
1279 mo = (omapi_object_t *)message;
1280
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);
1285 return status;
1286 }
1287
1288 if (rid) {
1289 omapi_handle_t handle;
1290 status = omapi_set_int_value (mo, (omapi_object_t *)0,
1291 "rid", (int)rid);
1292 if (status != ISC_R_SUCCESS) {
1293 omapi_message_dereference (&message, MDL);
1294 return status;
1295 }
1296
1297 status = omapi_object_handle (&handle, object);
1298 if (status != ISC_R_SUCCESS) {
1299 omapi_message_dereference (&message, MDL);
1300 return status;
1301 }
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);
1306 return status;
1307 }
1308 }
1309
1310 status = omapi_set_object_value (mo, (omapi_object_t *)0,
1311 "object", object);
1312 if (status != ISC_R_SUCCESS) {
1313 omapi_message_dereference (&message, MDL);
1314 return status;
1315 }
1316
1317 status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0);
1318 omapi_message_dereference (&message, MDL);
1319 return status;
1320 }