]> git.ipfire.org Git - thirdparty/dhcp.git/blob - omapip/protocol.c
[master] Addes addtional HMAC TSIG algorithms to DDNS
[thirdparty/dhcp.git] / omapip / protocol.c
1 /* protocol.c
2
3 Functions supporting the object management protocol... */
4
5 /*
6 * Copyright (c) 2009,2012,2014 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 */
29
30 #include "dhcpd.h"
31
32 #include <omapip/omapip_p.h>
33
34 OMAPI_OBJECT_ALLOC (omapi_protocol, omapi_protocol_object_t,
35 omapi_type_protocol)
36 OMAPI_OBJECT_ALLOC (omapi_protocol_listener, omapi_protocol_listener_object_t,
37 omapi_type_protocol_listener)
38
39 isc_result_t omapi_protocol_connect (omapi_object_t *h,
40 const char *server_name,
41 unsigned port,
42 omapi_object_t *a)
43 {
44 isc_result_t rstatus, status;
45 omapi_protocol_object_t *obj;
46
47 #ifdef DEBUG_PROTOCOL
48 log_debug ("omapi_protocol_connect(%s port=%d)", server_name, port);
49 #endif
50
51 obj = (omapi_protocol_object_t *)0;
52 status = omapi_protocol_allocate (&obj, MDL);
53 if (status != ISC_R_SUCCESS)
54 return status;
55
56 rstatus = omapi_connect ((omapi_object_t *)obj, server_name, port);
57 if (rstatus != ISC_R_SUCCESS && rstatus != DHCP_R_INCOMPLETE) {
58 omapi_protocol_dereference (&obj, MDL);
59 return rstatus;
60 }
61 status = omapi_object_reference (&h -> outer,
62 (omapi_object_t *)obj, MDL);
63 if (status != ISC_R_SUCCESS) {
64 omapi_protocol_dereference (&obj, MDL);
65 return status;
66 }
67 status = omapi_object_reference (&obj -> inner, h, MDL);
68 if (status != ISC_R_SUCCESS) {
69 omapi_protocol_dereference (&obj, MDL);
70 return status;
71 }
72
73 /* If we were passed a default authenticator, store it now. We'll
74 open it once we're connected. */
75 if (a) {
76 obj -> default_auth =
77 dmalloc (sizeof(omapi_remote_auth_t), MDL);
78 if (!obj -> default_auth) {
79 omapi_protocol_dereference (&obj, MDL);
80 return ISC_R_NOMEMORY;
81 }
82
83 obj -> default_auth -> next = (omapi_remote_auth_t *)0;
84 status = omapi_object_reference (&obj -> default_auth -> a,
85 a, MDL);
86 if (status != ISC_R_SUCCESS) {
87 dfree (obj -> default_auth, MDL);
88 omapi_protocol_dereference (&obj, MDL);
89 return status;
90 }
91
92 obj -> insecure = 0;
93 rstatus = DHCP_R_INCOMPLETE;
94 } else {
95 obj -> insecure = 1;
96 #if 0
97 status = ISC_R_SUCCESS;
98 #endif
99 }
100
101 omapi_protocol_dereference (&obj, MDL);
102 return rstatus;
103 }
104
105 /* Send the protocol introduction message. */
106 isc_result_t omapi_protocol_send_intro (omapi_object_t *h,
107 unsigned ver,
108 unsigned hsize)
109 {
110 isc_result_t status;
111 omapi_protocol_object_t *p;
112
113 #ifdef DEBUG_PROTOCOL
114 log_debug ("omapi_protocol_send_intro()");
115 #endif
116
117 if (h -> type != omapi_type_protocol)
118 return DHCP_R_INVALIDARG;
119 p = (omapi_protocol_object_t *)h;
120
121 if (!h -> outer || h -> outer -> type != omapi_type_connection)
122 return ISC_R_NOTCONNECTED;
123
124 status = omapi_connection_put_uint32 (h -> outer, ver);
125 if (status != ISC_R_SUCCESS)
126 return status;
127
128 status = omapi_connection_put_uint32 (h -> outer, hsize);
129
130 if (status != ISC_R_SUCCESS)
131 return status;
132
133 /* Require the other end to send an intro - this kicks off the
134 protocol input state machine. */
135 p -> state = omapi_protocol_intro_wait;
136 status = omapi_connection_require (h -> outer, 8);
137 if (status != ISC_R_SUCCESS && status != DHCP_R_NOTYET)
138 return status;
139
140 /* Make up an initial transaction ID for this connection. */
141 p -> next_xid = random ();
142 return ISC_R_SUCCESS;
143 }
144
145 #ifdef DEBUG_PROTOCOL
146 extern const char *omapi_message_op_name(int);
147 #endif /* DEBUG_PROTOCOL */
148
149 isc_result_t omapi_protocol_send_message (omapi_object_t *po,
150 omapi_object_t *id,
151 omapi_object_t *mo,
152 omapi_object_t *omo)
153 {
154 omapi_protocol_object_t *p;
155 omapi_object_t *c;
156 omapi_message_object_t *m, *om;
157 omapi_remote_auth_t *ra;
158 omapi_value_t *signature;
159 isc_result_t status;
160 unsigned auth_len;
161
162 if (po -> type != omapi_type_protocol ||
163 !po -> outer || po -> outer -> type != omapi_type_connection ||
164 mo -> type != omapi_type_message)
165 return DHCP_R_INVALIDARG;
166 if (omo && omo -> type != omapi_type_message)
167 return DHCP_R_INVALIDARG;
168 p = (omapi_protocol_object_t *)po;
169 c = (omapi_object_t *)(po -> outer);
170 m = (omapi_message_object_t *)mo;
171 om = (omapi_message_object_t *)omo;
172
173 #ifdef DEBUG_PROTOCOL
174 log_debug ("omapi_protocol_send_message(): "
175 "op=%s handle=%#lx id=%#lx rid=%#lx",
176 omapi_message_op_name (m->op),
177 (long)(m -> object ? m -> object -> handle : m -> handle),
178 (long)p -> next_xid, (long)m -> rid);
179 #endif
180
181 /* Find the authid to use for this message. */
182 if (id) {
183 for (ra = p -> remote_auth_list; ra; ra = ra -> next) {
184 if (ra -> a == id) {
185 break;
186 }
187 }
188
189 if (!ra)
190 return DHCP_R_KEY_UNKNOWN;
191 } else if (p -> remote_auth_list) {
192 ra = p -> default_auth;
193 } else {
194 ra = (omapi_remote_auth_t *)0;
195 }
196
197 if (ra) {
198 m -> authid = ra -> remote_handle;
199 status = omapi_object_reference (&m -> id_object,
200 ra -> a, MDL);
201 if (status != ISC_R_SUCCESS)
202 return status;
203 }
204
205 /* Write the ID of the authentication key we're using. */
206 status = omapi_connection_put_uint32 (c, ra ? ra -> remote_handle : 0);
207 if (status != ISC_R_SUCCESS) {
208 omapi_disconnect (c, 1);
209 return status;
210 }
211
212 /* Activate the authentication key on the connection. */
213 auth_len = 0;
214 if (ra) {
215 status = omapi_set_object_value (c, (omapi_object_t *)0,
216 "output-authenticator",
217 ra -> a);
218 if (status != ISC_R_SUCCESS) {
219 omapi_disconnect (c, 1);
220 return status;
221 }
222
223 status = omapi_connection_output_auth_length (c, &auth_len);
224 if (status != ISC_R_SUCCESS) {
225 omapi_disconnect (c, 1);
226 return status;
227 }
228 }
229
230 /* Write the authenticator length */
231 status = omapi_connection_put_uint32 (c, auth_len);
232 if (status != ISC_R_SUCCESS) {
233 omapi_disconnect (c, 1);
234 return status;
235 }
236
237 /* Write the opcode. */
238 status = omapi_connection_put_uint32 (c, m -> op);
239 if (status != ISC_R_SUCCESS) {
240 omapi_disconnect (c, 1);
241 return status;
242 }
243
244 /* Write the handle. If we've been given an explicit handle, use
245 that. Otherwise, use the handle of the object we're sending.
246 The caller is responsible for arranging for one of these handles
247 to be set (or not). */
248 status = omapi_connection_put_uint32 (c, (m -> h
249 ? m -> h
250 : (m -> object
251 ? m -> object -> handle
252 : 0)));
253 if (status != ISC_R_SUCCESS) {
254 omapi_disconnect (c, 1);
255 return status;
256 }
257
258 /* Set and write the transaction ID. */
259 m -> id = p -> next_xid++;
260 status = omapi_connection_put_uint32 (c, m -> id);
261 if (status != ISC_R_SUCCESS) {
262 omapi_disconnect (c, 1);
263 return status;
264 }
265
266 /* Write the transaction ID of the message to which this is a
267 response, if there is such a message. */
268 status = omapi_connection_put_uint32 (c, om ? om -> id : m -> rid);
269 if (status != ISC_R_SUCCESS) {
270 omapi_disconnect (c, 1);
271 return status;
272 }
273
274 /* Stuff out the name/value pairs specific to this message. */
275 status = omapi_stuff_values (c, id, (omapi_object_t *)m);
276 if (status != ISC_R_SUCCESS) {
277 omapi_disconnect (c, 1);
278 return status;
279 }
280
281 /* Write the zero-length name that terminates the list of name/value
282 pairs specific to the message. */
283 status = omapi_connection_put_uint16 (c, 0);
284 if (status != ISC_R_SUCCESS) {
285 omapi_disconnect (c, 1);
286 return status;
287 }
288
289 /* Stuff out all the published name/value pairs in the object that's
290 being sent in the message, if there is one. */
291 if (m -> object) {
292 status = omapi_stuff_values (c, id, m -> object);
293 if (status != ISC_R_SUCCESS) {
294 omapi_disconnect (c, 1);
295 return status;
296 }
297 }
298
299 /* Write the zero-length name that terminates the list of name/value
300 pairs for the associated object. */
301 status = omapi_connection_put_uint16 (c, 0);
302 if (status != ISC_R_SUCCESS) {
303 omapi_disconnect (c, 1);
304 return status;
305 }
306
307 if (ra) {
308 /* Calculate the message signature. */
309 signature = (omapi_value_t *)0;
310 status = omapi_get_value_str (c, (omapi_object_t *)0,
311 "output-signature", &signature);
312 if (status != ISC_R_SUCCESS) {
313 omapi_disconnect (c, 1);
314 return status;
315 }
316
317 /* Write the authenticator... */
318 status = (omapi_connection_copyin
319 (c, signature -> value -> u.buffer.value,
320 signature -> value -> u.buffer.len));
321 omapi_value_dereference (&signature, MDL);
322 if (status != ISC_R_SUCCESS) {
323 omapi_disconnect (c, 1);
324 return status;
325 }
326
327 /* Dectivate the authentication key on the connection. */
328 status = omapi_set_value_str (c, (omapi_object_t *)0,
329 "output-authenticator",
330 (omapi_typed_data_t *)0);
331 if (status != ISC_R_SUCCESS) {
332 omapi_disconnect (c, 1);
333 return status;
334 }
335 }
336
337 if (!omo) {
338 omapi_protocol_reference (&m -> protocol_object, p, MDL);
339 }
340 return ISC_R_SUCCESS;
341 }
342
343
344 isc_result_t omapi_protocol_signal_handler (omapi_object_t *h,
345 const char *name, va_list ap)
346 {
347 isc_result_t status;
348 omapi_protocol_object_t *p;
349 omapi_object_t *c;
350 omapi_message_object_t *m;
351 omapi_value_t *signature = NULL;
352 u_int16_t nlen;
353 u_int32_t vlen;
354 u_int32_t th;
355 #if defined (DEBUG_MEMORY_LEAKAGE)
356 unsigned long previous_outstanding = 0xDEADBEEF;
357 unsigned long connect_outstanding = 0xDEADBEEF;
358 #endif
359
360 if (h -> type != omapi_type_protocol) {
361 /* XXX shouldn't happen. Put an assert here? */
362 return ISC_R_UNEXPECTED;
363 }
364 p = (omapi_protocol_object_t *)h;
365
366 if (!strcmp (name, "connect")) {
367 #if defined (DEBUG_MEMORY_LEAKAGE)
368 connect_outstanding = dmalloc_outstanding;
369 #endif
370 /* Send the introductory message. */
371 status = omapi_protocol_send_intro
372 (h, OMAPI_PROTOCOL_VERSION,
373 sizeof (omapi_protocol_header_t));
374 if (status != ISC_R_SUCCESS) {
375 omapi_disconnect (p -> outer, 1);
376 return status;
377 }
378 return ISC_R_SUCCESS;
379 }
380
381 /* Should only receive these when opening the initial authenticator. */
382 if (!strcmp (name, "status")) {
383 status = va_arg (ap, isc_result_t);
384 if (status != ISC_R_SUCCESS) {
385 omapi_signal_in (h -> inner, "status", status,
386 (omapi_object_t *)0);
387 omapi_disconnect (p -> outer, 1);
388 return status;
389 } else {
390 return omapi_signal_in (h -> inner, "ready");
391 }
392 }
393
394 /* If we get a disconnect, dump memory usage. */
395 if (!strcmp (name, "disconnect")) {
396 #if defined (DEBUG_MEMORY_LEAKAGE)
397 if (connect_outstanding != 0xDEADBEEF) {
398 log_info ("generation %ld: %ld new, %ld outstanding, %ld%s",
399 dmalloc_generation,
400 dmalloc_outstanding - previous_outstanding,
401 dmalloc_outstanding, dmalloc_longterm, " long-term");
402 }
403 #endif
404 #if defined (DEBUG_MEMORY_LEAKAGE)
405 dmalloc_dump_outstanding ();
406 #endif
407 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
408 dump_rc_history (h);
409 #endif
410 for (m = omapi_registered_messages; m; m = m -> next) {
411 if (m -> protocol_object == p) {
412 if (m -> object)
413 omapi_signal (m -> object, "disconnect");
414 }
415 }
416
417 /* XXX */
418 return ISC_R_SUCCESS;
419 }
420
421 /* Not a signal we recognize? */
422 if (strcmp (name, "ready")) {
423 if (p -> inner && p -> inner -> type -> signal_handler)
424 return (*(p -> inner -> type -> signal_handler)) (h,
425 name,
426 ap);
427 return ISC_R_NOTFOUND;
428 }
429
430 if (!p -> outer || p -> outer -> type != omapi_type_connection)
431 return DHCP_R_INVALIDARG;
432 c = p -> outer;
433
434 /* We get here because we requested that we be woken up after
435 some number of bytes were read, and that number of bytes
436 has in fact been read. */
437 switch (p -> state) {
438 case omapi_protocol_intro_wait:
439 /* Get protocol version and header size in network
440 byte order. */
441 omapi_connection_get_uint32 (c, &p -> protocol_version);
442 omapi_connection_get_uint32 (c, &p -> header_size);
443
444 /* We currently only support the current protocol version. */
445 if (p -> protocol_version != OMAPI_PROTOCOL_VERSION) {
446 omapi_disconnect (c, 1);
447 return DHCP_R_VERSIONMISMATCH;
448 }
449
450 if (p -> header_size < sizeof (omapi_protocol_header_t)) {
451 omapi_disconnect (c, 1);
452 return DHCP_R_PROTOCOLERROR;
453 }
454
455 if (p -> default_auth) {
456 status = omapi_protocol_send_open
457 (h, (omapi_object_t *)0, "authenticator",
458 p -> default_auth -> a,
459 OMAPI_NOTIFY_PROTOCOL);
460 if (status != ISC_R_SUCCESS) {
461 omapi_disconnect (c, 1);
462 return status;
463 }
464 } else {
465 status = omapi_signal_in (h -> inner, "ready");
466 }
467
468 to_header_wait:
469 /* The next thing we're expecting is a message header. */
470 p -> state = omapi_protocol_header_wait;
471
472 /* Register a need for the number of bytes in a
473 header, and if we already have that many, process
474 them immediately. */
475 if ((omapi_connection_require (c, p -> header_size)) !=
476 ISC_R_SUCCESS)
477 break;
478 /* If we already have the data, fall through. */
479
480 case omapi_protocol_header_wait:
481 #if defined (DEBUG_MEMORY_LEAKAGE)
482 if (previous_outstanding != 0xDEADBEEF) {
483 log_info ("%s %ld: %ld new, %ld outstanding, %ld%s",
484 "generation", dmalloc_generation,
485 dmalloc_outstanding - previous_outstanding,
486 dmalloc_outstanding, dmalloc_longterm,
487 " long-term");
488 #endif
489 #if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
490 dmalloc_dump_outstanding ();
491 #endif
492 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
493 dump_rc_history (h);
494 #endif
495 #if defined (DEBUG_MEMORY_LEAKAGE)
496 }
497 previous_outstanding = dmalloc_outstanding;
498 #endif
499 status = omapi_message_new ((omapi_object_t **)&p -> message,
500 MDL);
501 if (status != ISC_R_SUCCESS) {
502 omapi_disconnect (c, 1);
503 return status;
504 }
505
506 p -> verify_result = ISC_R_SUCCESS;
507
508 /* Swap in the header... */
509 omapi_connection_get_uint32 (c, &p -> message -> authid);
510
511 /* Bind the authenticator to the message object. */
512 if (p -> message -> authid) {
513 status = (omapi_protocol_lookup_auth
514 (&p -> message -> id_object, h,
515 p -> message -> authid));
516 if (status != ISC_R_SUCCESS)
517 p -> verify_result = status;
518
519 /* Activate the authentication key. */
520 status = omapi_set_object_value
521 (c, (omapi_object_t *)0, "input-authenticator",
522 p -> message -> id_object);
523 if (status != ISC_R_SUCCESS) {
524 omapi_disconnect (c, 1);
525 return status;
526 }
527 }
528
529 omapi_connection_get_uint32 (c, &p -> message -> authlen);
530 omapi_connection_get_uint32 (c, &p -> message -> op);
531 omapi_connection_get_uint32 (c, &th);
532 p -> message -> h = th;
533 omapi_connection_get_uint32 (c, &p -> message -> id);
534 omapi_connection_get_uint32 (c, &p -> message -> rid);
535
536 /* If there was any extra header data, skip over it. */
537 if (p -> header_size > sizeof (omapi_protocol_header_t)) {
538 omapi_connection_copyout
539 (0, c, (p -> header_size -
540 sizeof (omapi_protocol_header_t)));
541 }
542
543 /* XXX must compute partial signature across the
544 XXX preceding bytes. Also, if authenticator
545 specifies encryption as well as signing, we may
546 have to decrypt the data on the way in. */
547
548 /* First we read in message-specific values, then object
549 values. */
550 p -> reading_message_values = 1;
551
552 need_name_length:
553 /* The next thing we're expecting is length of the
554 first name. */
555 p -> state = omapi_protocol_name_length_wait;
556
557 /* Wait for a 16-bit length. */
558 if ((omapi_connection_require (c, 2)) != ISC_R_SUCCESS)
559 break;
560 /* If it's already here, fall through. */
561
562 case omapi_protocol_name_length_wait:
563 omapi_connection_get_uint16 (c, &nlen);
564 /* A zero-length name means that we're done reading name+value
565 pairs. */
566 if (nlen == 0) {
567 /* If we've already read in the object, we are
568 done reading the message, but if we've just
569 finished reading in the values associated
570 with the message, we need to read the
571 object. */
572 if (p -> reading_message_values) {
573 p -> reading_message_values = 0;
574 goto need_name_length;
575 }
576
577 /* If the authenticator length is zero, there's no
578 signature to read in, so go straight to processing
579 the message. */
580 if (p -> message -> authlen == 0)
581 goto message_done;
582
583 /* The next thing we're expecting is the
584 message signature. */
585 p -> state = omapi_protocol_signature_wait;
586
587 /* Wait for the number of bytes specified for
588 the authenticator. If we already have it,
589 go read it in. */
590 if (omapi_connection_require
591 (c, p -> message -> authlen) == ISC_R_SUCCESS)
592 goto signature_wait;
593 break;
594 }
595
596 /* Allocate a buffer for the name. */
597 status = (omapi_data_string_new (&p -> name, nlen, MDL));
598 if (status != ISC_R_SUCCESS) {
599 omapi_disconnect (c, 1);
600 return ISC_R_NOMEMORY;
601 }
602 p -> state = omapi_protocol_name_wait;
603 if (omapi_connection_require (c, nlen) != ISC_R_SUCCESS)
604 break;
605 /* If it's already here, fall through. */
606
607 case omapi_protocol_name_wait:
608 omapi_connection_copyout (p -> name -> value, c,
609 p -> name -> len);
610 /* Wait for a 32-bit length. */
611 p -> state = omapi_protocol_value_length_wait;
612 if ((omapi_connection_require (c, 4)) != ISC_R_SUCCESS)
613 break;
614 /* If it's already here, fall through. */
615
616 case omapi_protocol_value_length_wait:
617 omapi_connection_get_uint32 (c, &vlen);
618
619 /* Zero-length values are allowed - if we get one, we
620 don't have to read any data for the value - just
621 get the next one, if there is a next one. */
622 if (!vlen)
623 goto insert_new_value;
624
625 status = omapi_typed_data_new (MDL, &p -> value,
626 omapi_datatype_data,
627 vlen);
628 if (status != ISC_R_SUCCESS) {
629 omapi_disconnect (c, 1);
630 return ISC_R_NOMEMORY;
631 }
632
633 p -> state = omapi_protocol_value_wait;
634 if (omapi_connection_require (c, vlen) != ISC_R_SUCCESS)
635 break;
636 /* If it's already here, fall through. */
637
638 case omapi_protocol_value_wait:
639 omapi_connection_copyout (p -> value -> u.buffer.value, c,
640 p -> value -> u.buffer.len);
641
642 insert_new_value:
643 if (p -> reading_message_values) {
644 status = (omapi_set_value
645 ((omapi_object_t *)p -> message,
646 p -> message -> id_object,
647 p -> name, p -> value));
648 } else {
649 if (!p -> message -> object) {
650 /* We need a generic object to hang off of the
651 incoming message. */
652 status = (omapi_generic_new
653 (&p -> message -> object, MDL));
654 if (status != ISC_R_SUCCESS) {
655 omapi_disconnect (c, 1);
656 return status;
657 }
658 }
659 status = (omapi_set_value
660 ((omapi_object_t *)p -> message -> object,
661 p -> message -> id_object,
662 p -> name, p -> value));
663 }
664 if (status != ISC_R_SUCCESS) {
665 omapi_disconnect (c, 1);
666 return status;
667 }
668 omapi_data_string_dereference (&p -> name, MDL);
669 if (p -> value)
670 omapi_typed_data_dereference (&p -> value, MDL);
671 goto need_name_length;
672
673 signature_wait:
674 case omapi_protocol_signature_wait:
675 if (p -> message -> id_object) {
676 /* Compute the signature of the message. */
677 status = omapi_get_value_str (c, (omapi_object_t *)0,
678 "input-signature",
679 &signature);
680 if (status != ISC_R_SUCCESS) {
681 omapi_disconnect (c, 1);
682 return status;
683 }
684
685 /* Disable the authentication key on the connection. */
686 status = omapi_set_value_str (c, (omapi_object_t *)0,
687 "input-authenticator",
688 (omapi_typed_data_t *)0);
689 if (status != ISC_R_SUCCESS) {
690 omapi_value_dereference (&signature, MDL);
691 omapi_disconnect (c, 1);
692 return status;
693 }
694 }
695
696 /* Read the authenticator. */
697 status = omapi_typed_data_new (MDL,
698 &p -> message -> authenticator,
699 omapi_datatype_data,
700 p -> message -> authlen);
701
702 if (status != ISC_R_SUCCESS) {
703 if (signature != NULL) {
704 omapi_value_dereference (&signature, MDL);
705 }
706 omapi_disconnect (c, 1);
707 return ISC_R_NOMEMORY;
708 }
709 omapi_connection_copyout
710 (p -> message -> authenticator -> u.buffer.value, c,
711 p -> message -> authlen);
712
713 /* Verify the signature. */
714 if (p -> message -> id_object &&
715 ((signature -> value -> u.buffer.len !=
716 p -> message -> authlen) ||
717 (memcmp (signature -> value -> u.buffer.value,
718 p -> message -> authenticator -> u.buffer.value,
719 p -> message -> authlen) != 0))) {
720 /* Invalid signature. */
721 p->verify_result = DHCP_R_INVALIDKEY;
722 }
723
724 if (signature != NULL) {
725 omapi_value_dereference (&signature, MDL);
726 }
727
728 /* Process the message. */
729 message_done:
730 if (p -> verify_result != ISC_R_SUCCESS) {
731 status = omapi_protocol_send_status
732 (h, (omapi_object_t *)0, p -> verify_result,
733 p -> message -> id, (char *)0);
734 } else {
735 status = omapi_message_process
736 ((omapi_object_t *)p -> message, h);
737 }
738 if (status != ISC_R_SUCCESS) {
739 omapi_disconnect (c, 1);
740 return ISC_R_NOMEMORY;
741 }
742
743 omapi_message_dereference (&p -> message, MDL);
744 #if defined (DEBUG_MEMORY_LEAKAGE)
745 log_info ("generation %ld: %ld new, %ld outstanding, %ld%s",
746 dmalloc_generation,
747 dmalloc_outstanding - previous_outstanding,
748 dmalloc_outstanding, dmalloc_longterm, " long-term");
749 #endif
750 #if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
751 dmalloc_dump_outstanding ();
752 #endif
753 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
754 dump_rc_history (h);
755 #endif
756 #if defined (DEBUG_MEMORY_LEAKAGE)
757 previous_outstanding = 0xDEADBEEF;
758 #endif
759 /* Now wait for the next message. */
760 goto to_header_wait;
761
762 default:
763 /* XXX should never get here. Assertion? */
764 break;
765 }
766 return ISC_R_SUCCESS;
767 }
768
769 isc_result_t omapi_protocol_add_auth (omapi_object_t *po,
770 omapi_object_t *ao,
771 omapi_handle_t handle)
772 {
773 omapi_protocol_object_t *p;
774 omapi_remote_auth_t *r;
775 isc_result_t status;
776
777 if (ao -> type != omapi_type_auth_key &&
778 (!ao -> inner || ao -> inner -> type != omapi_type_auth_key))
779 return DHCP_R_INVALIDARG;
780
781 if (po -> type != omapi_type_protocol)
782 return DHCP_R_INVALIDARG;
783 p = (omapi_protocol_object_t *)po;
784
785 #ifdef DEBUG_PROTOCOL
786 log_debug ("omapi_protocol_add_auth(name=%s)",
787 ((omapi_auth_key_t *)ao) -> name);
788 #endif
789
790 if (p -> verify_auth) {
791 status = (p -> verify_auth) (po, (omapi_auth_key_t *)ao);
792 if (status != ISC_R_SUCCESS)
793 return status;
794 }
795
796 /* If omapi_protocol_connect() was called with a default
797 authenticator, p -> default_auth will already be set,
798 but p -> remote_auth_list will not yet be initialized. */
799 if (p -> default_auth && !p -> remote_auth_list) {
800 if (p -> default_auth -> a != ao) {
801 /* Something just went horribly wrong. */
802 omapi_disconnect (p -> outer, 1);
803 return ISC_R_UNEXPECTED;
804 }
805
806 p -> remote_auth_list = p -> default_auth;
807 p -> default_auth -> remote_handle = handle;
808
809 return omapi_signal_in (p -> inner, "ready");
810 }
811
812 r = dmalloc (sizeof(*r), MDL);
813 if (!r)
814 return ISC_R_NOMEMORY;
815
816 status = omapi_object_reference (&r -> a, ao, MDL);
817 if (status != ISC_R_SUCCESS) {
818 dfree (r, MDL);
819 return status;
820 }
821
822 r -> remote_handle = handle;
823 r -> next = p -> remote_auth_list;
824 p -> remote_auth_list = r;
825
826 return ISC_R_SUCCESS;
827 }
828
829 isc_result_t omapi_protocol_lookup_auth (omapi_object_t **a,
830 omapi_object_t *po,
831 omapi_handle_t handle)
832 {
833 omapi_protocol_object_t *p;
834 omapi_remote_auth_t *r;
835
836 if (po -> type != omapi_type_protocol)
837 return DHCP_R_INVALIDARG;
838 p = (omapi_protocol_object_t *)po;
839
840 for (r = p -> remote_auth_list; r; r = r -> next)
841 if (r -> remote_handle == handle)
842 return omapi_object_reference (a, r -> a, MDL);
843
844 return DHCP_R_KEY_UNKNOWN;
845 }
846
847 isc_result_t omapi_protocol_set_value (omapi_object_t *h,
848 omapi_object_t *id,
849 omapi_data_string_t *name,
850 omapi_typed_data_t *value)
851 {
852 omapi_protocol_object_t *p;
853 omapi_remote_auth_t *r;
854
855 if (h -> type != omapi_type_protocol)
856 return DHCP_R_INVALIDARG;
857 p = (omapi_protocol_object_t *)h;
858
859 if (omapi_ds_strcmp (name, "default-authenticator") == 0) {
860 if (!value || value -> type != omapi_datatype_object)
861 return DHCP_R_INVALIDARG;
862
863 if (!value -> u.object) {
864 p -> default_auth = (omapi_remote_auth_t *)0;
865 } else {
866 for (r = p -> remote_auth_list; r; r = r -> next)
867 if (r -> a == value -> u.object)
868 break;
869
870 if (!r)
871 return DHCP_R_KEY_UNKNOWN;
872
873 p -> default_auth = r;
874 }
875
876 return ISC_R_SUCCESS;
877 }
878
879 if (h -> inner && h -> inner -> type -> set_value)
880 return (*(h -> inner -> type -> set_value))
881 (h -> inner, id, name, value);
882 return ISC_R_NOTFOUND;
883 }
884
885 isc_result_t omapi_protocol_get_value (omapi_object_t *h,
886 omapi_object_t *id,
887 omapi_data_string_t *name,
888 omapi_value_t **value)
889 {
890 omapi_protocol_object_t *p;
891
892 if (h -> type != omapi_type_protocol)
893 return DHCP_R_INVALIDARG;
894 p = (omapi_protocol_object_t *)h;
895
896 if (omapi_ds_strcmp (name, "default-authenticator") == 0) {
897 if (!p -> default_auth)
898 return ISC_R_NOTFOUND;
899
900 return omapi_make_object_value (value, name,
901 p -> default_auth -> a, MDL);
902 }
903
904 if (h -> inner && h -> inner -> type -> get_value)
905 return (*(h -> inner -> type -> get_value))
906 (h -> inner, id, name, value);
907 return ISC_R_NOTFOUND;
908 }
909
910 isc_result_t omapi_protocol_destroy (omapi_object_t *h,
911 const char *file, int line)
912 {
913 omapi_protocol_object_t *p;
914 if (h -> type != omapi_type_protocol)
915 return DHCP_R_INVALIDARG;
916 p = (omapi_protocol_object_t *)h;
917 if (p -> message)
918 omapi_message_dereference (&p -> message, file, line);
919
920 /* This will happen if: 1) A default authenticator is supplied to
921 omapi_protocol_connect(), and 2) something goes wrong before
922 the authenticator can be opened. */
923 if (p -> default_auth && !p -> remote_auth_list)
924 dfree (p -> default_auth, file, line);
925
926 while (p -> remote_auth_list) {
927 omapi_remote_auth_t *r = p -> remote_auth_list;
928 p -> remote_auth_list = p -> remote_auth_list -> next;
929 omapi_object_dereference (&r -> a, file, line);
930 dfree (r, file, line);
931 }
932 return ISC_R_SUCCESS;
933 }
934
935 /* Write all the published values associated with the object through the
936 specified connection. */
937
938 isc_result_t omapi_protocol_stuff_values (omapi_object_t *c,
939 omapi_object_t *id,
940 omapi_object_t *p)
941 {
942 if (p -> type != omapi_type_protocol)
943 return DHCP_R_INVALIDARG;
944
945 if (p -> inner && p -> inner -> type -> stuff_values)
946 return (*(p -> inner -> type -> stuff_values)) (c, id,
947 p -> inner);
948 return ISC_R_SUCCESS;
949 }
950
951 /* Returns a boolean indicating whether this protocol requires that
952 messages be authenticated or not. */
953
954 isc_boolean_t omapi_protocol_authenticated (omapi_object_t *h)
955 {
956 if (h -> type != omapi_type_protocol)
957 return isc_boolean_false;
958 if (((omapi_protocol_object_t *)h) -> insecure)
959 return isc_boolean_false;
960 else
961 return isc_boolean_true;
962 }
963
964 /* Sets the address and authenticator verification callbacks. The handle
965 is to a listener object, not a protocol object. */
966
967 isc_result_t omapi_protocol_configure_security (omapi_object_t *h,
968 isc_result_t (*verify_addr)
969 (omapi_object_t *,
970 omapi_addr_t *),
971 isc_result_t (*verify_auth)
972 (omapi_object_t *,
973 omapi_auth_key_t *))
974 {
975 omapi_protocol_listener_object_t *l;
976
977 if (h -> outer && h -> outer -> type == omapi_type_protocol_listener)
978 h = h -> outer;
979
980 if (h -> type != omapi_type_protocol_listener)
981 return DHCP_R_INVALIDARG;
982 l = (omapi_protocol_listener_object_t *)h;
983
984 l -> verify_auth = verify_auth;
985 l -> insecure = 0;
986
987 if (h -> outer != NULL) {
988 return omapi_listener_configure_security (h -> outer, verify_addr);
989 } else {
990 return DHCP_R_INVALIDARG;
991 }
992 }
993
994
995 /* Set up a listener for the omapi protocol. The handle stored points to
996 a listener object, not a protocol object. */
997
998 isc_result_t omapi_protocol_listen (omapi_object_t *h,
999 unsigned port,
1000 int max)
1001 {
1002 isc_result_t status;
1003 omapi_protocol_listener_object_t *obj;
1004
1005 obj = (omapi_protocol_listener_object_t *)0;
1006 status = omapi_protocol_listener_allocate (&obj, MDL);
1007 if (status != ISC_R_SUCCESS)
1008 return status;
1009
1010 status = omapi_object_reference (&h -> outer,
1011 (omapi_object_t *)obj, MDL);
1012 if (status != ISC_R_SUCCESS) {
1013 omapi_protocol_listener_dereference (&obj, MDL);
1014 return status;
1015 }
1016 status = omapi_object_reference (&obj -> inner, h, MDL);
1017 if (status != ISC_R_SUCCESS) {
1018 omapi_protocol_listener_dereference (&obj, MDL);
1019 return status;
1020 }
1021
1022 /* What a terrible default. */
1023 obj -> insecure = 1;
1024
1025 status = omapi_listen ((omapi_object_t *)obj, port, max);
1026 omapi_protocol_listener_dereference (&obj, MDL);
1027 return status;
1028 }
1029
1030 /* Signal handler for protocol listener - if we get a connect signal,
1031 create a new protocol connection, otherwise pass the signal down. */
1032
1033 isc_result_t omapi_protocol_listener_signal (omapi_object_t *o,
1034 const char *name, va_list ap)
1035 {
1036 isc_result_t status;
1037 omapi_object_t *c;
1038 omapi_protocol_object_t *obj;
1039 omapi_protocol_listener_object_t *p;
1040
1041 if (!o || o -> type != omapi_type_protocol_listener)
1042 return DHCP_R_INVALIDARG;
1043 p = (omapi_protocol_listener_object_t *)o;
1044
1045 /* Not a signal we recognize? */
1046 if (strcmp (name, "connect")) {
1047 if (p -> inner && p -> inner -> type -> signal_handler)
1048 return (*(p -> inner -> type -> signal_handler))
1049 (p -> inner, name, ap);
1050 return ISC_R_NOTFOUND;
1051 }
1052
1053 c = va_arg (ap, omapi_object_t *);
1054 if (!c || c -> type != omapi_type_connection)
1055 return DHCP_R_INVALIDARG;
1056
1057 obj = (omapi_protocol_object_t *)0;
1058 status = omapi_protocol_allocate (&obj, MDL);
1059 if (status != ISC_R_SUCCESS)
1060 return status;
1061
1062 obj -> verify_auth = p -> verify_auth;
1063 obj -> insecure = p -> insecure;
1064
1065 status = omapi_object_reference (&obj -> outer, c, MDL);
1066 if (status != ISC_R_SUCCESS) {
1067 lose:
1068 omapi_protocol_dereference (&obj, MDL);
1069 omapi_disconnect (c, 1);
1070 return status;
1071 }
1072
1073 status = omapi_object_reference (&c -> inner,
1074 (omapi_object_t *)obj, MDL);
1075 if (status != ISC_R_SUCCESS)
1076 goto lose;
1077
1078 /* Send the introductory message. */
1079 status = omapi_protocol_send_intro ((omapi_object_t *)obj,
1080 OMAPI_PROTOCOL_VERSION,
1081 sizeof (omapi_protocol_header_t));
1082 if (status != ISC_R_SUCCESS)
1083 goto lose;
1084
1085 omapi_protocol_dereference (&obj, MDL);
1086 return status;
1087 }
1088
1089 isc_result_t omapi_protocol_listener_set_value (omapi_object_t *h,
1090 omapi_object_t *id,
1091 omapi_data_string_t *name,
1092 omapi_typed_data_t *value)
1093 {
1094 if (h -> type != omapi_type_protocol_listener)
1095 return DHCP_R_INVALIDARG;
1096
1097 if (h -> inner && h -> inner -> type -> set_value)
1098 return (*(h -> inner -> type -> set_value))
1099 (h -> inner, id, name, value);
1100 return ISC_R_NOTFOUND;
1101 }
1102
1103 isc_result_t omapi_protocol_listener_get_value (omapi_object_t *h,
1104 omapi_object_t *id,
1105 omapi_data_string_t *name,
1106 omapi_value_t **value)
1107 {
1108 if (h -> type != omapi_type_protocol_listener)
1109 return DHCP_R_INVALIDARG;
1110
1111 if (h -> inner && h -> inner -> type -> get_value)
1112 return (*(h -> inner -> type -> get_value))
1113 (h -> inner, id, name, value);
1114 return ISC_R_NOTFOUND;
1115 }
1116
1117 isc_result_t omapi_protocol_listener_destroy (omapi_object_t *h,
1118 const char *file, int line)
1119 {
1120 if (h -> type != omapi_type_protocol_listener)
1121 return DHCP_R_INVALIDARG;
1122 return ISC_R_SUCCESS;
1123 }
1124
1125 /* Write all the published values associated with the object through the
1126 specified connection. */
1127
1128 isc_result_t omapi_protocol_listener_stuff (omapi_object_t *c,
1129 omapi_object_t *id,
1130 omapi_object_t *p)
1131 {
1132 if (p -> type != omapi_type_protocol_listener)
1133 return DHCP_R_INVALIDARG;
1134
1135 if (p -> inner && p -> inner -> type -> stuff_values)
1136 return (*(p -> inner -> type -> stuff_values)) (c, id,
1137 p -> inner);
1138 return ISC_R_SUCCESS;
1139 }
1140
1141 isc_result_t omapi_protocol_send_status (omapi_object_t *po,
1142 omapi_object_t *id,
1143 isc_result_t waitstatus,
1144 unsigned rid, const char *msg)
1145 {
1146 isc_result_t status;
1147 omapi_message_object_t *message = (omapi_message_object_t *)0;
1148 omapi_object_t *mo;
1149
1150 if (po -> type != omapi_type_protocol)
1151 return DHCP_R_INVALIDARG;
1152
1153 status = omapi_message_new ((omapi_object_t **)&message, MDL);
1154 if (status != ISC_R_SUCCESS)
1155 return status;
1156 mo = (omapi_object_t *)message;
1157
1158 status = omapi_set_int_value (mo, (omapi_object_t *)0,
1159 "op", OMAPI_OP_STATUS);
1160 if (status != ISC_R_SUCCESS) {
1161 omapi_message_dereference (&message, MDL);
1162 return status;
1163 }
1164
1165 status = omapi_set_int_value (mo, (omapi_object_t *)0,
1166 "rid", (int)rid);
1167 if (status != ISC_R_SUCCESS) {
1168 omapi_message_dereference (&message, MDL);
1169 return status;
1170 }
1171
1172 status = omapi_set_int_value (mo, (omapi_object_t *)0,
1173 "result", (int)waitstatus);
1174 if (status != ISC_R_SUCCESS) {
1175 omapi_message_dereference (&message, MDL);
1176 return status;
1177 }
1178
1179 /* If a message has been provided, send it. */
1180 if (msg) {
1181 status = omapi_set_string_value (mo, (omapi_object_t *)0,
1182 "message", msg);
1183 if (status != ISC_R_SUCCESS) {
1184 omapi_message_dereference (&message, MDL);
1185 return status;
1186 }
1187 }
1188
1189 status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0);
1190 omapi_message_dereference (&message, MDL);
1191 return status;
1192 }
1193
1194 /* The OMAPI_NOTIFY_PROTOCOL flag will cause the notify-object for the
1195 message to be set to the protocol object. This is used when opening
1196 the default authenticator. */
1197
1198 isc_result_t omapi_protocol_send_open (omapi_object_t *po,
1199 omapi_object_t *id,
1200 const char *type,
1201 omapi_object_t *object,
1202 unsigned flags)
1203 {
1204 isc_result_t status;
1205 omapi_message_object_t *message = (omapi_message_object_t *)0;
1206 omapi_object_t *mo;
1207
1208 if (po -> type != omapi_type_protocol)
1209 return DHCP_R_INVALIDARG;
1210
1211 status = omapi_message_new ((omapi_object_t **)&message, MDL);
1212 mo = (omapi_object_t *)message;
1213
1214 if (status == ISC_R_SUCCESS)
1215 status = omapi_set_int_value (mo, (omapi_object_t *)0,
1216 "op", OMAPI_OP_OPEN);
1217
1218 if (status == ISC_R_SUCCESS)
1219 status = omapi_set_object_value (mo, (omapi_object_t *)0,
1220 "object", object);
1221
1222 if ((flags & OMAPI_CREATE) && (status == ISC_R_SUCCESS))
1223 status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1224 "create", 1);
1225
1226 if ((flags & OMAPI_UPDATE) && (status == ISC_R_SUCCESS))
1227 status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1228 "update", 1);
1229
1230 if ((flags & OMAPI_EXCL) && (status == ISC_R_SUCCESS))
1231 status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1232 "exclusive", 1);
1233
1234 if ((flags & OMAPI_NOTIFY_PROTOCOL) && (status == ISC_R_SUCCESS))
1235 status = omapi_set_object_value (mo, (omapi_object_t *)0,
1236 "notify-object", po);
1237
1238 if (type && (status == ISC_R_SUCCESS))
1239 status = omapi_set_string_value (mo, (omapi_object_t *)0,
1240 "type", type);
1241
1242 if (status == ISC_R_SUCCESS)
1243 status = omapi_message_register (mo);
1244
1245 if (status == ISC_R_SUCCESS) {
1246 status = omapi_protocol_send_message (po, id, mo,
1247 (omapi_object_t *)0);
1248 if (status != ISC_R_SUCCESS)
1249 omapi_message_unregister (mo);
1250 }
1251
1252 if (message)
1253 omapi_message_dereference (&message, MDL);
1254
1255 return status;
1256 }
1257
1258 isc_result_t omapi_protocol_send_update (omapi_object_t *po,
1259 omapi_object_t *id,
1260 unsigned rid,
1261 omapi_object_t *object)
1262 {
1263 isc_result_t status;
1264 omapi_message_object_t *message = (omapi_message_object_t *)0;
1265 omapi_object_t *mo;
1266
1267 if (po -> type != omapi_type_protocol)
1268 return DHCP_R_INVALIDARG;
1269
1270 status = omapi_message_new ((omapi_object_t **)&message, MDL);
1271 if (status != ISC_R_SUCCESS)
1272 return status;
1273 mo = (omapi_object_t *)message;
1274
1275 status = omapi_set_int_value (mo, (omapi_object_t *)0,
1276 "op", OMAPI_OP_UPDATE);
1277 if (status != ISC_R_SUCCESS) {
1278 omapi_message_dereference (&message, MDL);
1279 return status;
1280 }
1281
1282 if (rid) {
1283 omapi_handle_t handle;
1284 status = omapi_set_int_value (mo, (omapi_object_t *)0,
1285 "rid", (int)rid);
1286 if (status != ISC_R_SUCCESS) {
1287 omapi_message_dereference (&message, MDL);
1288 return status;
1289 }
1290
1291 status = omapi_object_handle (&handle, object);
1292 if (status != ISC_R_SUCCESS) {
1293 omapi_message_dereference (&message, MDL);
1294 return status;
1295 }
1296 status = omapi_set_int_value (mo, (omapi_object_t *)0,
1297 "handle", (int)handle);
1298 if (status != ISC_R_SUCCESS) {
1299 omapi_message_dereference (&message, MDL);
1300 return status;
1301 }
1302 }
1303
1304 status = omapi_set_object_value (mo, (omapi_object_t *)0,
1305 "object", object);
1306 if (status != ISC_R_SUCCESS) {
1307 omapi_message_dereference (&message, MDL);
1308 return status;
1309 }
1310
1311 status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0);
1312 omapi_message_dereference (&message, MDL);
1313 return status;
1314 }