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