Merge from vendor branch DHCP:
[dragonfly.git] / contrib / dhcp-3.0 / omapip / protocol.c
1 /* protocol.c
2
3    Functions supporting the object management protocol... */
4
5 /*
6  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1999-2003 by Internet Software Consortium
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *
21  *   Internet Systems Consortium, Inc.
22  *   950 Charter Street
23  *   Redwood City, CA 94063
24  *   <info@isc.org>
25  *   http://www.isc.org/
26  *
27  * This software has been written for Internet Systems Consortium
28  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29  * To learn more about Internet Systems Consortium, see
30  * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
31  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
32  * ``http://www.nominum.com''.
33  */
34
35 #include <omapip/omapip_p.h>
36
37 OMAPI_OBJECT_ALLOC (omapi_protocol, omapi_protocol_object_t,
38                     omapi_type_protocol)
39 OMAPI_OBJECT_ALLOC (omapi_protocol_listener, omapi_protocol_listener_object_t,
40                     omapi_type_protocol_listener)
41
42 isc_result_t omapi_protocol_connect (omapi_object_t *h,
43                                      const char *server_name,
44                                      unsigned port,
45                                      omapi_object_t *a)
46 {
47         isc_result_t rstatus, status;
48         omapi_protocol_object_t *obj;
49
50 #ifdef DEBUG_PROTOCOL
51         log_debug ("omapi_protocol_connect(%s port=%d)", server_name, port);
52 #endif
53
54         obj = (omapi_protocol_object_t *)0;
55         status = omapi_protocol_allocate (&obj, MDL);
56         if (status != ISC_R_SUCCESS)
57                 return status;
58
59         rstatus = omapi_connect ((omapi_object_t *)obj, server_name, port);
60         if (rstatus != ISC_R_SUCCESS && rstatus != ISC_R_INCOMPLETE) {
61                 omapi_protocol_dereference (&obj, MDL);
62                 return rstatus;
63         }
64         status = omapi_object_reference (&h -> outer,
65                                          (omapi_object_t *)obj, MDL);
66         if (status != ISC_R_SUCCESS) {
67                 omapi_protocol_dereference (&obj, MDL);
68                 return status;
69         }
70         status = omapi_object_reference (&obj -> inner, h, MDL);
71         if (status != ISC_R_SUCCESS) {
72                 omapi_protocol_dereference (&obj, MDL);
73                 return status;
74         }
75
76         /* If we were passed a default authenticator, store it now.  We'll
77            open it once we're connected. */
78         if (a) {
79                 obj -> default_auth =
80                         dmalloc (sizeof(omapi_remote_auth_t), MDL);
81                 if (!obj -> default_auth) {
82                         omapi_protocol_dereference (&obj, MDL);
83                         return ISC_R_NOMEMORY;
84                 }
85
86                 obj -> default_auth -> next = (omapi_remote_auth_t *)0;
87                 status = omapi_object_reference (&obj -> default_auth -> a,
88                                                  a, MDL);
89                 if (status != ISC_R_SUCCESS) {
90                         dfree (obj -> default_auth, MDL);
91                         omapi_protocol_dereference (&obj, MDL);
92                         return status;
93                 }
94
95                 obj -> insecure = 0;
96                 rstatus = ISC_R_INCOMPLETE;
97         } else {
98                 obj -> insecure = 1;
99 #if 0
100                 status = ISC_R_SUCCESS;
101 #endif
102         }
103
104         omapi_protocol_dereference (&obj, MDL);
105         return rstatus;
106 }
107
108 /* Send the protocol introduction message. */
109 isc_result_t omapi_protocol_send_intro (omapi_object_t *h,
110                                         unsigned ver,
111                                         unsigned hsize)
112 {
113         isc_result_t status;
114         omapi_protocol_object_t *p;
115
116 #ifdef DEBUG_PROTOCOL
117         log_debug ("omapi_protocol_send_intro()");
118 #endif
119
120         if (h -> type != omapi_type_protocol)
121                 return ISC_R_INVALIDARG;
122         p = (omapi_protocol_object_t *)h;
123
124         if (!h -> outer || h -> outer -> type != omapi_type_connection)
125                 return ISC_R_NOTCONNECTED;
126
127         status = omapi_connection_put_uint32 (h -> outer, ver);
128         if (status != ISC_R_SUCCESS)
129                 return status;
130
131         status = omapi_connection_put_uint32 (h -> outer, hsize);
132
133         if (status != ISC_R_SUCCESS)
134                 return status;
135
136         /* Require the other end to send an intro - this kicks off the
137            protocol input state machine. */
138         p -> state = omapi_protocol_intro_wait;
139         status = omapi_connection_require (h -> outer, 8);
140         if (status != ISC_R_SUCCESS && status != ISC_R_NOTYET)
141                 return status;
142
143         /* Make up an initial transaction ID for this connection. */
144         p -> next_xid = random ();
145         return ISC_R_SUCCESS;
146 }
147
148 isc_result_t omapi_protocol_send_message (omapi_object_t *po,
149                                           omapi_object_t *id,
150                                           omapi_object_t *mo,
151                                           omapi_object_t *omo)
152 {
153         omapi_protocol_object_t *p;
154         omapi_object_t *c;
155         omapi_message_object_t *m, *om;
156         omapi_remote_auth_t *ra;
157         omapi_value_t *signature;
158         isc_result_t status;
159         u_int32_t foo;
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 ISC_R_INVALIDARG;
166         if (omo && omo -> type != omapi_type_message)
167                 return ISC_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=%ld  handle=%#lx  id=%#lx  rid=%#lx",
176                    (long)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 ISC_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;
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 ();
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
418         /* Not a signal we recognize? */
419         if (strcmp (name, "ready")) {
420                 if (p -> inner && p -> inner -> type -> signal_handler)
421                         return (*(p -> inner -> type -> signal_handler)) (h,
422                                                                           name,
423                                                                           ap);
424                 return ISC_R_NOTFOUND;
425         }
426
427         if (!p -> outer || p -> outer -> type != omapi_type_connection)
428                 return ISC_R_INVALIDARG;
429         c = p -> outer;
430
431         /* We get here because we requested that we be woken up after
432            some number of bytes were read, and that number of bytes
433            has in fact been read. */
434         switch (p -> state) {
435               case omapi_protocol_intro_wait:
436                 /* Get protocol version and header size in network
437                    byte order. */
438                 omapi_connection_get_uint32 (c, &p -> protocol_version);
439                 omapi_connection_get_uint32 (c, &p -> header_size);
440         
441                 /* We currently only support the current protocol version. */
442                 if (p -> protocol_version != OMAPI_PROTOCOL_VERSION) {
443                         omapi_disconnect (c, 1);
444                         return ISC_R_VERSIONMISMATCH;
445                 }
446
447                 if (p -> header_size < sizeof (omapi_protocol_header_t)) {
448                         omapi_disconnect (c, 1);
449                         return ISC_R_PROTOCOLERROR;
450                 }
451
452                 if (p -> default_auth) {
453                         status = omapi_protocol_send_open
454                                 (h, (omapi_object_t *)0, "authenticator",
455                                  p -> default_auth -> a,
456                                  OMAPI_NOTIFY_PROTOCOL);
457                         if (status != ISC_R_SUCCESS) {
458                                 omapi_disconnect (c, 1);
459                                 return status;
460                         }
461                 } else {
462                         status = omapi_signal_in (h -> inner, "ready");
463                 }
464
465               to_header_wait:
466                 /* The next thing we're expecting is a message header. */
467                 p -> state = omapi_protocol_header_wait;
468
469                 /* Register a need for the number of bytes in a
470                    header, and if we already have that many, process
471                    them immediately. */
472                 if ((omapi_connection_require (c, p -> header_size)) !=
473                     ISC_R_SUCCESS)
474                         break;
475                 /* If we already have the data, fall through. */
476
477               case omapi_protocol_header_wait:
478 #if defined (DEBUG_MEMORY_LEAKAGE)
479                 if (previous_outstanding != 0xDEADBEEF) {
480                         log_info ("%s %ld: %ld new, %ld outstanding, %ld%s",
481                                   "generation", dmalloc_generation,
482                                   dmalloc_outstanding - previous_outstanding,
483                                   dmalloc_outstanding, dmalloc_longterm,
484                                   " long-term");
485 #endif
486 #if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
487                         dmalloc_dump_outstanding ();
488 #endif
489 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
490                         dump_rc_history ();
491 #endif
492 #if defined (DEBUG_MEMORY_LEAKAGE)
493                 }
494                 previous_outstanding = dmalloc_outstanding;
495 #endif
496                 status = omapi_message_new ((omapi_object_t **)&p -> message,
497                                             MDL);
498                 if (status != ISC_R_SUCCESS) {
499                         omapi_disconnect (c, 1);
500                         return status;
501                 }
502
503                 p -> verify_result = ISC_R_SUCCESS;
504
505                 /* Swap in the header... */
506                 omapi_connection_get_uint32 (c, &p -> message -> authid);
507
508                 /* Bind the authenticator to the message object. */
509                 if (p -> message -> authid) {
510                         status = (omapi_protocol_lookup_auth
511                                   (&p -> message -> id_object, h,
512                                    p -> message -> authid));
513                         if (status != ISC_R_SUCCESS)
514                                 p -> verify_result = status;
515
516                         /* Activate the authentication key. */
517                         status = omapi_set_object_value
518                                 (c, (omapi_object_t *)0, "input-authenticator",
519                                  p -> message -> id_object);
520                         if (status != ISC_R_SUCCESS) {
521                                 omapi_disconnect (c, 1);
522                                 return status;
523                         }
524                 }
525
526                 omapi_connection_get_uint32 (c, &p -> message -> authlen);
527                 omapi_connection_get_uint32 (c, &p -> message -> op);
528                 omapi_connection_get_uint32 (c, &th);
529                 p -> message -> h = th;
530                 omapi_connection_get_uint32 (c, &p -> message -> id);
531                 omapi_connection_get_uint32 (c, &p -> message -> rid);
532
533                 /* If there was any extra header data, skip over it. */
534                 if (p -> header_size > sizeof (omapi_protocol_header_t)) {
535                         omapi_connection_copyout
536                                 (0, c, (p -> header_size -
537                                         sizeof (omapi_protocol_header_t)));
538                 }
539                                                      
540                 /* XXX must compute partial signature across the
541                    XXX preceding bytes.    Also, if authenticator
542                    specifies encryption as well as signing, we may
543                    have to decrypt the data on the way in. */
544
545                 /* First we read in message-specific values, then object
546                    values. */
547                 p -> reading_message_values = 1;
548
549               need_name_length:
550                 /* The next thing we're expecting is length of the
551                    first name. */
552                 p -> state = omapi_protocol_name_length_wait;
553
554                 /* Wait for a 16-bit length. */
555                 if ((omapi_connection_require (c, 2)) != ISC_R_SUCCESS)
556                         break;
557                 /* If it's already here, fall through. */
558
559               case omapi_protocol_name_length_wait:
560                 omapi_connection_get_uint16 (c, &nlen);
561                 /* A zero-length name means that we're done reading name+value
562                    pairs. */
563                 if (nlen == 0) {
564                         /* If we've already read in the object, we are
565                            done reading the message, but if we've just
566                            finished reading in the values associated
567                            with the message, we need to read the
568                            object. */
569                         if (p -> reading_message_values) {
570                                 p -> reading_message_values = 0;
571                                 goto need_name_length;
572                         }
573
574                         /* If the authenticator length is zero, there's no
575                            signature to read in, so go straight to processing
576                            the message. */
577                         if (p -> message -> authlen == 0)
578                                 goto message_done;
579
580                         /* The next thing we're expecting is the
581                            message signature. */
582                         p -> state = omapi_protocol_signature_wait;
583
584                         /* Wait for the number of bytes specified for
585                            the authenticator.  If we already have it,
586                            go read it in. */
587                         if (omapi_connection_require
588                             (c, p -> message -> authlen) == ISC_R_SUCCESS)
589                                 goto signature_wait;
590                         break;
591                 }
592
593                 /* Allocate a buffer for the name. */
594                 status = (omapi_data_string_new (&p -> name, nlen, MDL));
595                 if (status != ISC_R_SUCCESS) {
596                         omapi_disconnect (c, 1);
597                         return ISC_R_NOMEMORY;
598                 }
599                 p -> state = omapi_protocol_name_wait;
600                 if (omapi_connection_require (c, nlen) != ISC_R_SUCCESS)
601                         break;
602                 /* If it's already here, fall through. */
603                                              
604               case omapi_protocol_name_wait:
605                 omapi_connection_copyout (p -> name -> value, c,
606                                           p -> name -> len);
607                 /* Wait for a 32-bit length. */
608                 p -> state = omapi_protocol_value_length_wait;
609                 if ((omapi_connection_require (c, 4)) != ISC_R_SUCCESS)
610                         break;
611                 /* If it's already here, fall through. */
612
613               case omapi_protocol_value_length_wait:
614                 omapi_connection_get_uint32 (c, &vlen);
615
616                 /* Zero-length values are allowed - if we get one, we
617                    don't have to read any data for the value - just
618                    get the next one, if there is a next one. */
619                 if (!vlen)
620                         goto insert_new_value;
621
622                 status = omapi_typed_data_new (MDL, &p -> value,
623                                                omapi_datatype_data,
624                                                vlen);
625                 if (status != ISC_R_SUCCESS) {
626                         omapi_disconnect (c, 1);
627                         return ISC_R_NOMEMORY;
628                 }
629
630                 p -> state = omapi_protocol_value_wait;
631                 if (omapi_connection_require (c, vlen) != ISC_R_SUCCESS)
632                         break;
633                 /* If it's already here, fall through. */
634                                              
635               case omapi_protocol_value_wait:
636                 omapi_connection_copyout (p -> value -> u.buffer.value, c,
637                                           p -> value -> u.buffer.len);
638
639               insert_new_value:
640                 if (p -> reading_message_values) {
641                         status = (omapi_set_value
642                                   ((omapi_object_t *)p -> message,
643                                    p -> message -> id_object,
644                                    p -> name, p -> value));
645                 } else {
646                         if (!p -> message -> object) {
647                                 /* We need a generic object to hang off of the
648                                    incoming message. */
649                                 status = (omapi_generic_new
650                                           (&p -> message -> object, MDL));
651                                 if (status != ISC_R_SUCCESS) {
652                                         omapi_disconnect (c, 1);
653                                         return status;
654                                 }
655                         }
656                         status = (omapi_set_value
657                                   ((omapi_object_t *)p -> message -> object,
658                                    p -> message -> id_object,
659                                    p -> name, p -> value));
660                 }
661                 if (status != ISC_R_SUCCESS) {
662                         omapi_disconnect (c, 1);
663                         return status;
664                 }
665                 omapi_data_string_dereference (&p -> name, MDL);
666                 if (p -> value)
667                         omapi_typed_data_dereference (&p -> value, MDL);
668                 goto need_name_length;
669
670               signature_wait:
671               case omapi_protocol_signature_wait:
672                 if (p -> message -> id_object) {
673                         /* Compute the signature of the message. */
674                         signature = (omapi_value_t *)0;
675                         status = omapi_get_value_str (c, (omapi_object_t *)0,
676                                                       "input-signature",
677                                                       &signature);
678                         if (status != ISC_R_SUCCESS) {
679                                 omapi_disconnect (c, 1);
680                                 return status;
681                         }
682
683                         /* Disable the authentication key on the connection. */
684                         status = omapi_set_value_str (c, (omapi_object_t *)0,
685                                                       "input-authenticator",
686                                                       (omapi_typed_data_t *)0);
687                         if (status != ISC_R_SUCCESS) {
688                                 omapi_value_dereference (&signature, MDL);
689                                 omapi_disconnect (c, 1);
690                                 return status;
691                         }
692                 }
693
694                 /* Read the authenticator. */
695                 status = omapi_typed_data_new (MDL,
696                                                &p -> message -> authenticator,
697                                                omapi_datatype_data,
698                                                p -> message -> authlen);
699                         
700                 if (status != ISC_R_SUCCESS) {
701                         omapi_value_dereference (&signature, MDL);
702                         omapi_disconnect (c, 1);
703                         return ISC_R_NOMEMORY;
704                 }
705                 omapi_connection_copyout
706                         (p -> message -> authenticator -> u.buffer.value, c,
707                          p -> message -> authlen);
708
709                 /* Verify the signature. */
710                 if (p -> message -> id_object &&
711                     ((signature -> value -> u.buffer.len !=
712                       p -> message -> authlen) ||
713                      (memcmp (signature -> value -> u.buffer.value,
714                               p -> message -> authenticator -> u.buffer.value,
715                               p -> message -> authlen) != 0))) {
716                         /* Invalid signature. */
717                         p -> verify_result = ISC_R_INVALIDKEY;
718                 }
719
720                 omapi_value_dereference (&signature, MDL);
721
722                 /* Process the message. */
723               message_done:
724                 if (p -> verify_result != ISC_R_SUCCESS) {
725                         status = omapi_protocol_send_status
726                                 (h, (omapi_object_t *)0, p -> verify_result,
727                                  p -> message -> id, (char *)0);
728                 } else {
729                         status = omapi_message_process
730                                 ((omapi_object_t *)p -> message, h);
731                 }
732                 if (status != ISC_R_SUCCESS) {
733                         omapi_disconnect (c, 1);
734                         return ISC_R_NOMEMORY;
735                 }
736
737                 omapi_message_dereference (&p -> message, MDL);
738 #if defined (DEBUG_MEMORY_LEAKAGE)
739                 log_info ("generation %ld: %ld new, %ld outstanding, %ld%s",
740                           dmalloc_generation,
741                           dmalloc_outstanding - previous_outstanding,
742                           dmalloc_outstanding, dmalloc_longterm, " long-term");
743 #endif
744 #if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL))
745                 dmalloc_dump_outstanding ();
746 #endif
747 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
748                 dump_rc_history ();
749 #endif
750 #if defined (DEBUG_MEMORY_LEAKAGE)
751                 previous_outstanding = 0xDEADBEEF;
752 #endif
753                 /* Now wait for the next message. */
754                 goto to_header_wait;            
755
756               default:
757                 /* XXX should never get here.   Assertion? */
758                 break;
759         }
760         return ISC_R_SUCCESS;
761 }
762
763 isc_result_t omapi_protocol_add_auth (omapi_object_t *po,
764                                       omapi_object_t *ao,
765                                       omapi_handle_t handle)
766 {
767         omapi_protocol_object_t *p;
768         omapi_remote_auth_t *r;
769         isc_result_t status;
770
771         if (ao -> type != omapi_type_auth_key &&
772             (!ao -> inner || ao -> inner -> type != omapi_type_auth_key))
773                 return ISC_R_INVALIDARG;
774
775         if (po -> type != omapi_type_protocol)
776                 return ISC_R_INVALIDARG;
777         p = (omapi_protocol_object_t *)po;
778
779 #ifdef DEBUG_PROTOCOL
780         log_debug ("omapi_protocol_add_auth(name=%s)",
781                    ((omapi_auth_key_t *)ao) -> name);
782 #endif
783
784         if (p -> verify_auth) {
785                 status = (p -> verify_auth) (po, (omapi_auth_key_t *)ao);
786                 if (status != ISC_R_SUCCESS)
787                         return status;
788         }
789
790         /* If omapi_protocol_connect() was called with a default
791            authenticator, p -> default_auth will already be set,
792            but p -> remote_auth_list will not yet be initialized. */
793         if (p -> default_auth && !p -> remote_auth_list) {
794                 if (p -> default_auth -> a != ao) {
795                         /* Something just went horribly wrong. */
796                         omapi_disconnect (p -> outer, 1);
797                         return ISC_R_UNEXPECTED;
798                 }
799
800                 p -> remote_auth_list = p -> default_auth;
801                 p -> default_auth -> remote_handle = handle;
802
803                 return omapi_signal_in (p -> inner, "ready");
804         }
805
806         r = dmalloc (sizeof(*r), MDL);
807         if (!r)
808                 return ISC_R_NOMEMORY;
809
810         status = omapi_object_reference (&r -> a, ao, MDL);
811         if (status != ISC_R_SUCCESS) {
812                 dfree (r, MDL);
813                 return status;
814         }
815
816         r -> remote_handle = handle;
817         r -> next = p -> remote_auth_list;
818         p -> remote_auth_list = r;
819
820         return ISC_R_SUCCESS;
821 }
822
823 isc_result_t omapi_protocol_lookup_auth (omapi_object_t **a,
824                                          omapi_object_t *po,
825                                          omapi_handle_t handle)
826 {
827         omapi_protocol_object_t *p;
828         omapi_remote_auth_t *r;
829
830         if (po -> type != omapi_type_protocol)
831                 return ISC_R_INVALIDARG;
832         p = (omapi_protocol_object_t *)po;
833
834         for (r = p -> remote_auth_list; r; r = r -> next)
835                 if (r -> remote_handle == handle)
836                         return omapi_object_reference (a, r -> a, MDL);
837
838         return ISC_R_KEY_UNKNOWN;
839 }
840
841 isc_result_t omapi_protocol_set_value (omapi_object_t *h,
842                                        omapi_object_t *id,
843                                        omapi_data_string_t *name,
844                                        omapi_typed_data_t *value)
845 {
846         omapi_protocol_object_t *p;
847         omapi_remote_auth_t *r;
848
849         if (h -> type != omapi_type_protocol)
850                 return ISC_R_INVALIDARG;
851         p = (omapi_protocol_object_t *)h;
852
853         if (omapi_ds_strcmp (name, "default-authenticator") == 0) {
854                 if (value -> type != omapi_datatype_object)
855                         return ISC_R_INVALIDARG;
856
857                 if (!value || !value -> u.object) {
858                         p -> default_auth = (omapi_remote_auth_t *)0;
859                 } else {
860                         for (r = p -> remote_auth_list; r; r = r -> next)
861                                 if (r -> a == value -> u.object)
862                                         break;
863
864                         if (!r)
865                                 return ISC_R_KEY_UNKNOWN;
866
867                         p -> default_auth = r;
868                 }
869
870                 return ISC_R_SUCCESS;
871         }
872
873         if (h -> inner && h -> inner -> type -> set_value)
874                 return (*(h -> inner -> type -> set_value))
875                         (h -> inner, id, name, value);
876         return ISC_R_NOTFOUND;
877 }
878
879 isc_result_t omapi_protocol_get_value (omapi_object_t *h,
880                                        omapi_object_t *id,
881                                        omapi_data_string_t *name,
882                                        omapi_value_t **value)
883 {
884         omapi_protocol_object_t *p;
885
886         if (h -> type != omapi_type_protocol)
887                 return ISC_R_INVALIDARG;
888         p = (omapi_protocol_object_t *)h;
889
890         if (omapi_ds_strcmp (name, "default-authenticator") == 0) {
891                 if (!p -> default_auth)
892                         return ISC_R_NOTFOUND;
893
894                 return omapi_make_object_value (value, name,
895                                                 p -> default_auth -> a, MDL);
896         }
897         
898         if (h -> inner && h -> inner -> type -> get_value)
899                 return (*(h -> inner -> type -> get_value))
900                         (h -> inner, id, name, value);
901         return ISC_R_NOTFOUND;
902 }
903
904 isc_result_t omapi_protocol_destroy (omapi_object_t *h,
905                                      const char *file, int line)
906 {
907         omapi_protocol_object_t *p;
908         if (h -> type != omapi_type_protocol)
909                 return ISC_R_INVALIDARG;
910         p = (omapi_protocol_object_t *)h;
911         if (p -> message)
912                 omapi_message_dereference (&p -> message, file, line);
913
914         /* This will happen if: 1) A default authenticator is supplied to
915            omapi_protocol_connect(), and 2) something goes wrong before
916            the authenticator can be opened. */
917         if (p -> default_auth && !p -> remote_auth_list)
918                 dfree (p -> default_auth, file, line);
919
920         while (p -> remote_auth_list) {
921                 omapi_remote_auth_t *r = p -> remote_auth_list -> next;
922                 p -> remote_auth_list = r;
923                 if (r) {
924                         omapi_object_dereference (&r -> a, file, line);
925                         dfree (r, file, line);
926                 }
927         }
928         return ISC_R_SUCCESS;
929 }
930
931 /* Write all the published values associated with the object through the
932    specified connection. */
933
934 isc_result_t omapi_protocol_stuff_values (omapi_object_t *c,
935                                           omapi_object_t *id,
936                                           omapi_object_t *p)
937 {
938         int i;
939
940         if (p -> type != omapi_type_protocol)
941                 return ISC_R_INVALIDARG;
942
943         if (p -> inner && p -> inner -> type -> stuff_values)
944                 return (*(p -> inner -> type -> stuff_values)) (c, id,
945                                                                 p -> inner);
946         return ISC_R_SUCCESS;
947 }
948
949 /* Returns a boolean indicating whether this protocol requires that
950    messages be authenticated or not. */
951
952 isc_boolean_t omapi_protocol_authenticated (omapi_object_t *h)
953 {
954         if (h -> type != omapi_type_protocol)
955                 return isc_boolean_false;
956         if (((omapi_protocol_object_t *)h) -> insecure)
957                 return isc_boolean_false;
958         else
959                 return isc_boolean_true;
960 }
961
962 /* Sets the address and authenticator verification callbacks.  The handle
963    is to a listener object, not a protocol object. */
964
965 isc_result_t omapi_protocol_configure_security (omapi_object_t *h,
966                                                 isc_result_t (*verify_addr)
967                                                  (omapi_object_t *,
968                                                   omapi_addr_t *),
969                                                 isc_result_t (*verify_auth)
970                                                  (omapi_object_t *,
971                                                   omapi_auth_key_t *))
972 {
973         omapi_protocol_listener_object_t *l;
974
975         if (h -> outer && h -> outer -> type == omapi_type_protocol_listener)
976                 h = h -> outer;
977
978         if (h -> type != omapi_type_protocol_listener)
979                 return ISC_R_INVALIDARG;
980         l = (omapi_protocol_listener_object_t *)h;
981
982         l -> verify_auth = verify_auth;
983         l -> insecure = 0;
984
985         return omapi_listener_configure_security (h -> outer, verify_addr);
986 }
987                                               
988
989 /* Set up a listener for the omapi protocol.    The handle stored points to
990    a listener object, not a protocol object. */
991
992 isc_result_t omapi_protocol_listen (omapi_object_t *h,
993                                     unsigned port,
994                                     int max)
995 {
996         isc_result_t status;
997         omapi_protocol_listener_object_t *obj;
998
999         obj = (omapi_protocol_listener_object_t *)0;
1000         status = omapi_protocol_listener_allocate (&obj, MDL);
1001         if (status != ISC_R_SUCCESS)
1002                 return status;
1003
1004         status = omapi_object_reference (&h -> outer,
1005                                          (omapi_object_t *)obj, MDL);
1006         if (status != ISC_R_SUCCESS) {
1007                 omapi_protocol_listener_dereference (&obj, MDL);
1008                 return status;
1009         }
1010         status = omapi_object_reference (&obj -> inner, h, MDL);
1011         if (status != ISC_R_SUCCESS) {
1012                 omapi_protocol_listener_dereference (&obj, MDL);
1013                 return status;
1014         }
1015
1016         /* What a terrible default. */
1017         obj -> insecure = 1;
1018
1019         status = omapi_listen ((omapi_object_t *)obj, port, max);
1020         omapi_protocol_listener_dereference (&obj, MDL);
1021         return status;
1022 }
1023
1024 /* Signal handler for protocol listener - if we get a connect signal,
1025    create a new protocol connection, otherwise pass the signal down. */
1026
1027 isc_result_t omapi_protocol_listener_signal (omapi_object_t *o,
1028                                              const char *name, va_list ap)
1029 {
1030         isc_result_t status;
1031         omapi_object_t *c;
1032         omapi_protocol_object_t *obj;
1033         omapi_protocol_listener_object_t *p;
1034
1035         if (!o || o -> type != omapi_type_protocol_listener)
1036                 return ISC_R_INVALIDARG;
1037         p = (omapi_protocol_listener_object_t *)o;
1038
1039         /* Not a signal we recognize? */
1040         if (strcmp (name, "connect")) {
1041                 if (p -> inner && p -> inner -> type -> signal_handler)
1042                         return (*(p -> inner -> type -> signal_handler))
1043                                 (p -> inner, name, ap);
1044                 return ISC_R_NOTFOUND;
1045         }
1046
1047         c = va_arg (ap, omapi_object_t *);
1048         if (!c || c -> type != omapi_type_connection)
1049                 return ISC_R_INVALIDARG;
1050
1051         obj = (omapi_protocol_object_t *)0;
1052         status = omapi_protocol_allocate (&obj, MDL);
1053         if (status != ISC_R_SUCCESS)
1054                 return status;
1055
1056         obj -> verify_auth = p -> verify_auth;
1057         obj -> insecure = p -> insecure;
1058
1059         status = omapi_object_reference (&obj -> outer, c, MDL);
1060         if (status != ISC_R_SUCCESS) {
1061               lose:
1062                 omapi_protocol_dereference (&obj, MDL);
1063                 omapi_disconnect (c, 1);
1064                 return status;
1065         }
1066
1067         status = omapi_object_reference (&c -> inner,
1068                                          (omapi_object_t *)obj, MDL);
1069         if (status != ISC_R_SUCCESS)
1070                 goto lose;
1071
1072         /* Send the introductory message. */
1073         status = omapi_protocol_send_intro ((omapi_object_t *)obj,
1074                                             OMAPI_PROTOCOL_VERSION,
1075                                             sizeof (omapi_protocol_header_t));
1076         if (status != ISC_R_SUCCESS)
1077                 goto lose;
1078
1079         omapi_protocol_dereference (&obj, MDL);
1080         return status;
1081 }
1082
1083 isc_result_t omapi_protocol_listener_set_value (omapi_object_t *h,
1084                                                 omapi_object_t *id,
1085                                                 omapi_data_string_t *name,
1086                                                 omapi_typed_data_t *value)
1087 {
1088         if (h -> type != omapi_type_protocol_listener)
1089                 return ISC_R_INVALIDARG;
1090         
1091         if (h -> inner && h -> inner -> type -> set_value)
1092                 return (*(h -> inner -> type -> set_value))
1093                         (h -> inner, id, name, value);
1094         return ISC_R_NOTFOUND;
1095 }
1096
1097 isc_result_t omapi_protocol_listener_get_value (omapi_object_t *h,
1098                                                 omapi_object_t *id,
1099                                                 omapi_data_string_t *name,
1100                                                 omapi_value_t **value)
1101 {
1102         if (h -> type != omapi_type_protocol_listener)
1103                 return ISC_R_INVALIDARG;
1104         
1105         if (h -> inner && h -> inner -> type -> get_value)
1106                 return (*(h -> inner -> type -> get_value))
1107                         (h -> inner, id, name, value);
1108         return ISC_R_NOTFOUND;
1109 }
1110
1111 isc_result_t omapi_protocol_listener_destroy (omapi_object_t *h,
1112                                               const char *file, int line)
1113 {
1114         if (h -> type != omapi_type_protocol_listener)
1115                 return ISC_R_INVALIDARG;
1116         return ISC_R_SUCCESS;
1117 }
1118
1119 /* Write all the published values associated with the object through the
1120    specified connection. */
1121
1122 isc_result_t omapi_protocol_listener_stuff (omapi_object_t *c,
1123                                             omapi_object_t *id,
1124                                             omapi_object_t *p)
1125 {
1126         int i;
1127
1128         if (p -> type != omapi_type_protocol_listener)
1129                 return ISC_R_INVALIDARG;
1130
1131         if (p -> inner && p -> inner -> type -> stuff_values)
1132                 return (*(p -> inner -> type -> stuff_values)) (c, id,
1133                                                                 p -> inner);
1134         return ISC_R_SUCCESS;
1135 }
1136
1137 isc_result_t omapi_protocol_send_status (omapi_object_t *po,
1138                                          omapi_object_t *id,
1139                                          isc_result_t waitstatus,
1140                                          unsigned rid, const char *msg)
1141 {
1142         isc_result_t status;
1143         omapi_message_object_t *message = (omapi_message_object_t *)0;
1144         omapi_object_t *mo;
1145
1146         if (po -> type != omapi_type_protocol)
1147                 return ISC_R_INVALIDARG;
1148
1149         status = omapi_message_new ((omapi_object_t **)&message, MDL);
1150         if (status != ISC_R_SUCCESS)
1151                 return status;
1152         mo = (omapi_object_t *)message;
1153
1154         status = omapi_set_int_value (mo, (omapi_object_t *)0,
1155                                       "op", OMAPI_OP_STATUS);
1156         if (status != ISC_R_SUCCESS) {
1157                 omapi_message_dereference (&message, MDL);
1158                 return status;
1159         }
1160
1161         status = omapi_set_int_value (mo, (omapi_object_t *)0,
1162                                       "rid", (int)rid);
1163         if (status != ISC_R_SUCCESS) {
1164                 omapi_message_dereference (&message, MDL);
1165                 return status;
1166         }
1167
1168         status = omapi_set_int_value (mo, (omapi_object_t *)0,
1169                                       "result", (int)waitstatus);
1170         if (status != ISC_R_SUCCESS) {
1171                 omapi_message_dereference (&message, MDL);
1172                 return status;
1173         }
1174
1175         /* If a message has been provided, send it. */
1176         if (msg) {
1177                 status = omapi_set_string_value (mo, (omapi_object_t *)0,
1178                                                  "message", msg);
1179                 if (status != ISC_R_SUCCESS) {
1180                         omapi_message_dereference (&message, MDL);
1181                         return status;
1182                 }
1183         }
1184
1185         status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0);
1186         omapi_message_dereference (&message, MDL);
1187         return status;
1188 }
1189
1190 /* The OMAPI_NOTIFY_PROTOCOL flag will cause the notify-object for the
1191    message to be set to the protocol object.  This is used when opening
1192    the default authenticator. */
1193
1194 isc_result_t omapi_protocol_send_open (omapi_object_t *po,
1195                                        omapi_object_t *id,
1196                                        const char *type,
1197                                        omapi_object_t *object,
1198                                        unsigned flags)
1199 {
1200         isc_result_t status;
1201         omapi_message_object_t *message = (omapi_message_object_t *)0;
1202         omapi_object_t *mo;
1203
1204         if (po -> type != omapi_type_protocol)
1205                 return ISC_R_INVALIDARG;
1206
1207         status = omapi_message_new ((omapi_object_t **)&message, MDL);
1208         mo = (omapi_object_t *)message;
1209
1210         if (status == ISC_R_SUCCESS)
1211                 status = omapi_set_int_value (mo, (omapi_object_t *)0,
1212                                               "op", OMAPI_OP_OPEN);
1213
1214         if (status == ISC_R_SUCCESS)
1215                 status = omapi_set_object_value (mo, (omapi_object_t *)0,
1216                                                  "object", object);
1217
1218         if ((flags & OMAPI_CREATE) && (status == ISC_R_SUCCESS))
1219                 status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1220                                                   "create", 1);
1221
1222         if ((flags & OMAPI_UPDATE) && (status == ISC_R_SUCCESS))
1223                 status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1224                                                   "update", 1);
1225
1226         if ((flags & OMAPI_EXCL) && (status == ISC_R_SUCCESS))
1227                 status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1228                                                   "exclusive", 1);
1229
1230         if ((flags & OMAPI_NOTIFY_PROTOCOL) && (status == ISC_R_SUCCESS))
1231                 status = omapi_set_object_value (mo, (omapi_object_t *)0,
1232                                                  "notify-object", po);
1233
1234         if (type && (status == ISC_R_SUCCESS))
1235                 status = omapi_set_string_value (mo, (omapi_object_t *)0,
1236                                                  "type", type);
1237
1238         if (status == ISC_R_SUCCESS)
1239                 status = omapi_message_register (mo);
1240
1241         if (status == ISC_R_SUCCESS) {
1242                 status = omapi_protocol_send_message (po, id, mo,
1243                                                       (omapi_object_t *)0);
1244                 if (status != ISC_R_SUCCESS)
1245                         omapi_message_unregister (mo);
1246         }
1247
1248         if (message)
1249                 omapi_message_dereference (&message, MDL);
1250
1251         return status;
1252 }
1253
1254 isc_result_t omapi_protocol_send_update (omapi_object_t *po,
1255                                          omapi_object_t *id,
1256                                          unsigned rid,
1257                                          omapi_object_t *object)
1258 {
1259         isc_result_t status;
1260         omapi_message_object_t *message = (omapi_message_object_t *)0;
1261         omapi_object_t *mo;
1262
1263         if (po -> type != omapi_type_protocol)
1264                 return ISC_R_INVALIDARG;
1265
1266         status = omapi_message_new ((omapi_object_t **)&message, MDL);
1267         if (status != ISC_R_SUCCESS)
1268                 return status;
1269         mo = (omapi_object_t *)message;
1270
1271         status = omapi_set_int_value (mo, (omapi_object_t *)0,
1272                                       "op", OMAPI_OP_UPDATE);
1273         if (status != ISC_R_SUCCESS) {
1274                 omapi_message_dereference (&message, MDL);
1275                 return status;
1276         }
1277
1278         if (rid) {
1279                 omapi_handle_t handle;
1280                 status = omapi_set_int_value (mo, (omapi_object_t *)0,
1281                                               "rid", (int)rid);
1282                 if (status != ISC_R_SUCCESS) {
1283                         omapi_message_dereference (&message, MDL);
1284                         return status;
1285                 }
1286
1287                 status = omapi_object_handle (&handle, object);
1288                 if (status != ISC_R_SUCCESS) {
1289                         omapi_message_dereference (&message, MDL);
1290                         return status;
1291                 }
1292                 status = omapi_set_int_value (mo, (omapi_object_t *)0,
1293                                               "handle", (int)handle);
1294                 if (status != ISC_R_SUCCESS) {
1295                         omapi_message_dereference (&message, MDL);
1296                         return status;
1297                 }
1298         }               
1299                 
1300         status = omapi_set_object_value (mo, (omapi_object_t *)0,
1301                                          "object", object);
1302         if (status != ISC_R_SUCCESS) {
1303                 omapi_message_dereference (&message, MDL);
1304                 return status;
1305         }
1306
1307         status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0);
1308         omapi_message_dereference (&message, MDL);
1309         return status;
1310 }