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