1: /* protocol.c
2:
3: Functions supporting the object management protocol... */
4:
5: /*
6: * Copyright (c) 2009,2012 by Internet Systems Consortium, Inc. ("ISC")
7: * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
8: * Copyright (c) 1999-2003 by Internet Software Consortium
9: *
10: * Permission to use, copy, modify, and distribute this software for any
11: * purpose with or without fee is hereby granted, provided that the above
12: * copyright notice and this permission notice appear in all copies.
13: *
14: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21: *
22: * Internet Systems Consortium, Inc.
23: * 950 Charter Street
24: * Redwood City, CA 94063
25: * <info@isc.org>
26: * https://www.isc.org/
27: *
28: * This software has been written for Internet Systems Consortium
29: * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
30: * To learn more about Internet Systems Consortium, see
31: * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
32: * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
33: * ``http://www.nominum.com''.
34: */
35:
36: #include "dhcpd.h"
37:
38: #include <omapip/omapip_p.h>
39:
40: OMAPI_OBJECT_ALLOC (omapi_protocol, omapi_protocol_object_t,
41: omapi_type_protocol)
42: OMAPI_OBJECT_ALLOC (omapi_protocol_listener, omapi_protocol_listener_object_t,
43: omapi_type_protocol_listener)
44:
45: isc_result_t omapi_protocol_connect (omapi_object_t *h,
46: const char *server_name,
47: unsigned port,
48: omapi_object_t *a)
49: {
50: isc_result_t rstatus, status;
51: omapi_protocol_object_t *obj;
52:
53: #ifdef DEBUG_PROTOCOL
54: log_debug ("omapi_protocol_connect(%s port=%d)", server_name, port);
55: #endif
56:
57: obj = (omapi_protocol_object_t *)0;
58: status = omapi_protocol_allocate (&obj, MDL);
59: if (status != ISC_R_SUCCESS)
60: return status;
61:
62: rstatus = omapi_connect ((omapi_object_t *)obj, server_name, port);
63: if (rstatus != ISC_R_SUCCESS && rstatus != ISC_R_INCOMPLETE) {
64: omapi_protocol_dereference (&obj, MDL);
65: return rstatus;
66: }
67: status = omapi_object_reference (&h -> outer,
68: (omapi_object_t *)obj, MDL);
69: if (status != ISC_R_SUCCESS) {
70: omapi_protocol_dereference (&obj, MDL);
71: return status;
72: }
73: status = omapi_object_reference (&obj -> inner, h, MDL);
74: if (status != ISC_R_SUCCESS) {
75: omapi_protocol_dereference (&obj, MDL);
76: return status;
77: }
78:
79: /* If we were passed a default authenticator, store it now. We'll
80: open it once we're connected. */
81: if (a) {
82: obj -> default_auth =
83: dmalloc (sizeof(omapi_remote_auth_t), MDL);
84: if (!obj -> default_auth) {
85: omapi_protocol_dereference (&obj, MDL);
86: return ISC_R_NOMEMORY;
87: }
88:
89: obj -> default_auth -> next = (omapi_remote_auth_t *)0;
90: status = omapi_object_reference (&obj -> default_auth -> a,
91: a, MDL);
92: if (status != ISC_R_SUCCESS) {
93: dfree (obj -> default_auth, MDL);
94: omapi_protocol_dereference (&obj, MDL);
95: return status;
96: }
97:
98: obj -> insecure = 0;
99: rstatus = ISC_R_INCOMPLETE;
100: } else {
101: obj -> insecure = 1;
102: #if 0
103: status = ISC_R_SUCCESS;
104: #endif
105: }
106:
107: omapi_protocol_dereference (&obj, MDL);
108: return rstatus;
109: }
110:
111: /* Send the protocol introduction message. */
112: isc_result_t omapi_protocol_send_intro (omapi_object_t *h,
113: unsigned ver,
114: unsigned hsize)
115: {
116: isc_result_t status;
117: omapi_protocol_object_t *p;
118:
119: #ifdef DEBUG_PROTOCOL
120: log_debug ("omapi_protocol_send_intro()");
121: #endif
122:
123: if (h -> type != omapi_type_protocol)
124: return ISC_R_INVALIDARG;
125: p = (omapi_protocol_object_t *)h;
126:
127: if (!h -> outer || h -> outer -> type != omapi_type_connection)
128: return ISC_R_NOTCONNECTED;
129:
130: status = omapi_connection_put_uint32 (h -> outer, ver);
131: if (status != ISC_R_SUCCESS)
132: return status;
133:
134: status = omapi_connection_put_uint32 (h -> outer, hsize);
135:
136: if (status != ISC_R_SUCCESS)
137: return status;
138:
139: /* Require the other end to send an intro - this kicks off the
140: protocol input state machine. */
141: p -> state = omapi_protocol_intro_wait;
142: status = omapi_connection_require (h -> outer, 8);
143: if (status != ISC_R_SUCCESS && status != ISC_R_NOTYET)
144: return status;
145:
146: /* Make up an initial transaction ID for this connection. */
147: p -> next_xid = random ();
148: return ISC_R_SUCCESS;
149: }
150:
151: #ifdef DEBUG_PROTOCOL
152: extern const char *omapi_message_op_name(int);
153: #endif /* DEBUG_PROTOCOL */
154:
155: isc_result_t omapi_protocol_send_message (omapi_object_t *po,
156: omapi_object_t *id,
157: omapi_object_t *mo,
158: omapi_object_t *omo)
159: {
160: omapi_protocol_object_t *p;
161: omapi_object_t *c;
162: omapi_message_object_t *m, *om;
163: omapi_remote_auth_t *ra;
164: omapi_value_t *signature;
165: isc_result_t status;
166: unsigned auth_len;
167:
168: if (po -> type != omapi_type_protocol ||
169: !po -> outer || po -> outer -> type != omapi_type_connection ||
170: mo -> type != omapi_type_message)
171: return ISC_R_INVALIDARG;
172: if (omo && omo -> type != omapi_type_message)
173: return ISC_R_INVALIDARG;
174: p = (omapi_protocol_object_t *)po;
175: c = (omapi_object_t *)(po -> outer);
176: m = (omapi_message_object_t *)mo;
177: om = (omapi_message_object_t *)omo;
178:
179: #ifdef DEBUG_PROTOCOL
180: log_debug ("omapi_protocol_send_message(): "
181: "op=%s handle=%#lx id=%#lx rid=%#lx",
182: omapi_message_op_name (m->op),
183: (long)(m -> object ? m -> object -> handle : m -> handle),
184: (long)p -> next_xid, (long)m -> rid);
185: #endif
186:
187: /* Find the authid to use for this message. */
188: if (id) {
189: for (ra = p -> remote_auth_list; ra; ra = ra -> next) {
190: if (ra -> a == id) {
191: break;
192: }
193: }
194:
195: if (!ra)
196: return ISC_R_KEY_UNKNOWN;
197: } else if (p -> remote_auth_list) {
198: ra = p -> default_auth;
199: } else {
200: ra = (omapi_remote_auth_t *)0;
201: }
202:
203: if (ra) {
204: m -> authid = ra -> remote_handle;
205: status = omapi_object_reference (&m -> id_object,
206: ra -> a, MDL);
207: if (status != ISC_R_SUCCESS)
208: return status;
209: }
210:
211: /* Write the ID of the authentication key we're using. */
212: status = omapi_connection_put_uint32 (c, ra ? ra -> remote_handle : 0);
213: if (status != ISC_R_SUCCESS) {
214: omapi_disconnect (c, 1);
215: return status;
216: }
217:
218: /* Activate the authentication key on the connection. */
219: auth_len = 0;
220: if (ra) {
221: status = omapi_set_object_value (c, (omapi_object_t *)0,
222: "output-authenticator",
223: ra -> a);
224: if (status != ISC_R_SUCCESS) {
225: omapi_disconnect (c, 1);
226: return status;
227: }
228:
229: status = omapi_connection_output_auth_length (c, &auth_len);
230: if (status != ISC_R_SUCCESS) {
231: omapi_disconnect (c, 1);
232: return status;
233: }
234: }
235:
236: /* Write the authenticator length */
237: status = omapi_connection_put_uint32 (c, auth_len);
238: if (status != ISC_R_SUCCESS) {
239: omapi_disconnect (c, 1);
240: return status;
241: }
242:
243: /* Write the opcode. */
244: status = omapi_connection_put_uint32 (c, m -> op);
245: if (status != ISC_R_SUCCESS) {
246: omapi_disconnect (c, 1);
247: return status;
248: }
249:
250: /* Write the handle. If we've been given an explicit handle, use
251: that. Otherwise, use the handle of the object we're sending.
252: The caller is responsible for arranging for one of these handles
253: to be set (or not). */
254: status = omapi_connection_put_uint32 (c, (m -> h
255: ? m -> h
256: : (m -> object
257: ? m -> object -> handle
258: : 0)));
259: if (status != ISC_R_SUCCESS) {
260: omapi_disconnect (c, 1);
261: return status;
262: }
263:
264: /* Set and write the transaction ID. */
265: m -> id = p -> next_xid++;
266: status = omapi_connection_put_uint32 (c, m -> id);
267: if (status != ISC_R_SUCCESS) {
268: omapi_disconnect (c, 1);
269: return status;
270: }
271:
272: /* Write the transaction ID of the message to which this is a
273: response, if there is such a message. */
274: status = omapi_connection_put_uint32 (c, om ? om -> id : m -> rid);
275: if (status != ISC_R_SUCCESS) {
276: omapi_disconnect (c, 1);
277: return status;
278: }
279:
280: /* Stuff out the name/value pairs specific to this message. */
281: status = omapi_stuff_values (c, id, (omapi_object_t *)m);
282: if (status != ISC_R_SUCCESS) {
283: omapi_disconnect (c, 1);
284: return status;
285: }
286:
287: /* Write the zero-length name that terminates the list of name/value
288: pairs specific to the message. */
289: status = omapi_connection_put_uint16 (c, 0);
290: if (status != ISC_R_SUCCESS) {
291: omapi_disconnect (c, 1);
292: return status;
293: }
294:
295: /* Stuff out all the published name/value pairs in the object that's
296: being sent in the message, if there is one. */
297: if (m -> object) {
298: status = omapi_stuff_values (c, id, m -> object);
299: if (status != ISC_R_SUCCESS) {
300: omapi_disconnect (c, 1);
301: return status;
302: }
303: }
304:
305: /* Write the zero-length name that terminates the list of name/value
306: pairs for the associated object. */
307: status = omapi_connection_put_uint16 (c, 0);
308: if (status != ISC_R_SUCCESS) {
309: omapi_disconnect (c, 1);
310: return status;
311: }
312:
313: if (ra) {
314: /* Calculate the message signature. */
315: signature = (omapi_value_t *)0;
316: status = omapi_get_value_str (c, (omapi_object_t *)0,
317: "output-signature", &signature);
318: if (status != ISC_R_SUCCESS) {
319: omapi_disconnect (c, 1);
320: return status;
321: }
322:
323: /* Write the authenticator... */
324: status = (omapi_connection_copyin
325: (c, signature -> value -> u.buffer.value,
326: signature -> value -> u.buffer.len));
327: omapi_value_dereference (&signature, MDL);
328: if (status != ISC_R_SUCCESS) {
329: omapi_disconnect (c, 1);
330: return status;
331: }
332:
333: /* Dectivate the authentication key on the connection. */
334: status = omapi_set_value_str (c, (omapi_object_t *)0,
335: "output-authenticator",
336: (omapi_typed_data_t *)0);
337: if (status != ISC_R_SUCCESS) {
338: omapi_disconnect (c, 1);
339: return status;
340: }
341: }
342:
343: if (!omo) {
344: omapi_protocol_reference (&m -> protocol_object, p, MDL);
345: }
346: return ISC_R_SUCCESS;
347: }
348:
349:
350: isc_result_t omapi_protocol_signal_handler (omapi_object_t *h,
351: const char *name, va_list ap)
352: {
353: isc_result_t status;
354: omapi_protocol_object_t *p;
355: omapi_object_t *c;
356: omapi_message_object_t *m;
357: omapi_value_t *signature;
358: u_int16_t nlen;
359: u_int32_t vlen;
360: u_int32_t th;
361: #if defined (DEBUG_MEMORY_LEAKAGE)
362: unsigned long previous_outstanding = 0xDEADBEEF;
363: unsigned long connect_outstanding = 0xDEADBEEF;
364: #endif
365:
366: if (h -> type != omapi_type_protocol) {
367: /* XXX shouldn't happen. Put an assert here? */
368: return ISC_R_UNEXPECTED;
369: }
370: p = (omapi_protocol_object_t *)h;
371:
372: if (!strcmp (name, "connect")) {
373: #if defined (DEBUG_MEMORY_LEAKAGE)
374: connect_outstanding = dmalloc_outstanding;
375: #endif
376: /* Send the introductory message. */
377: status = omapi_protocol_send_intro
378: (h, OMAPI_PROTOCOL_VERSION,
379: sizeof (omapi_protocol_header_t));
380: if (status != ISC_R_SUCCESS) {
381: omapi_disconnect (p -> outer, 1);
382: return status;
383: }
384: return ISC_R_SUCCESS;
385: }
386:
387: /* Should only receive these when opening the initial authenticator. */
388: if (!strcmp (name, "status")) {
389: status = va_arg (ap, isc_result_t);
390: if (status != ISC_R_SUCCESS) {
391: omapi_signal_in (h -> inner, "status", status,
392: (omapi_object_t *)0);
393: omapi_disconnect (p -> outer, 1);
394: return status;
395: } else {
396: return omapi_signal_in (h -> inner, "ready");
397: }
398: }
399:
400: /* If we get a disconnect, dump memory usage. */
401: if (!strcmp (name, "disconnect")) {
402: #if defined (DEBUG_MEMORY_LEAKAGE)
403: if (connect_outstanding != 0xDEADBEEF) {
404: log_info ("generation %ld: %ld new, %ld outstanding, %ld%s",
405: dmalloc_generation,
406: dmalloc_outstanding - previous_outstanding,
407: dmalloc_outstanding, dmalloc_longterm, " long-term");
408: }
409: #endif
410: #if defined (DEBUG_MEMORY_LEAKAGE)
411: dmalloc_dump_outstanding ();
412: #endif
413: #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
414: dump_rc_history (h);
415: #endif
416: for (m = omapi_registered_messages; m; m = m -> next) {
417: if (m -> protocol_object == p) {
418: if (m -> object)
419: omapi_signal (m -> object, "disconnect");
420: }
421: }
422:
423: /* XXX */
424: return ISC_R_SUCCESS;
425: }
426:
427: /* Not a signal we recognize? */
428: if (strcmp (name, "ready")) {
429: if (p -> inner && p -> inner -> type -> signal_handler)
430: return (*(p -> inner -> type -> signal_handler)) (h,
431: name,
432: ap);
433: return ISC_R_NOTFOUND;
434: }
435:
436: if (!p -> outer || p -> outer -> type != omapi_type_connection)
437: return 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 (h);
500: #endif
501: #if defined (DEBUG_MEMORY_LEAKAGE)
502: }
503: previous_outstanding = dmalloc_outstanding;
504: #endif
505: status = omapi_message_new ((omapi_object_t **)&p -> message,
506: MDL);
507: if (status != ISC_R_SUCCESS) {
508: omapi_disconnect (c, 1);
509: return status;
510: }
511:
512: p -> verify_result = ISC_R_SUCCESS;
513:
514: /* Swap in the header... */
515: omapi_connection_get_uint32 (c, &p -> message -> authid);
516:
517: /* Bind the authenticator to the message object. */
518: if (p -> message -> authid) {
519: status = (omapi_protocol_lookup_auth
520: (&p -> message -> id_object, h,
521: p -> message -> authid));
522: if (status != ISC_R_SUCCESS)
523: p -> verify_result = status;
524:
525: /* Activate the authentication key. */
526: status = omapi_set_object_value
527: (c, (omapi_object_t *)0, "input-authenticator",
528: p -> message -> id_object);
529: if (status != ISC_R_SUCCESS) {
530: omapi_disconnect (c, 1);
531: return status;
532: }
533: }
534:
535: omapi_connection_get_uint32 (c, &p -> message -> authlen);
536: omapi_connection_get_uint32 (c, &p -> message -> op);
537: omapi_connection_get_uint32 (c, &th);
538: p -> message -> h = th;
539: omapi_connection_get_uint32 (c, &p -> message -> id);
540: omapi_connection_get_uint32 (c, &p -> message -> rid);
541:
542: /* If there was any extra header data, skip over it. */
543: if (p -> header_size > sizeof (omapi_protocol_header_t)) {
544: omapi_connection_copyout
545: (0, c, (p -> header_size -
546: sizeof (omapi_protocol_header_t)));
547: }
548:
549: /* XXX must compute partial signature across the
550: XXX preceding bytes. Also, if authenticator
551: specifies encryption as well as signing, we may
552: have to decrypt the data on the way in. */
553:
554: /* First we read in message-specific values, then object
555: values. */
556: p -> reading_message_values = 1;
557:
558: need_name_length:
559: /* The next thing we're expecting is length of the
560: first name. */
561: p -> state = omapi_protocol_name_length_wait;
562:
563: /* Wait for a 16-bit length. */
564: if ((omapi_connection_require (c, 2)) != ISC_R_SUCCESS)
565: break;
566: /* If it's already here, fall through. */
567:
568: case omapi_protocol_name_length_wait:
569: omapi_connection_get_uint16 (c, &nlen);
570: /* A zero-length name means that we're done reading name+value
571: pairs. */
572: if (nlen == 0) {
573: /* If we've already read in the object, we are
574: done reading the message, but if we've just
575: finished reading in the values associated
576: with the message, we need to read the
577: object. */
578: if (p -> reading_message_values) {
579: p -> reading_message_values = 0;
580: goto need_name_length;
581: }
582:
583: /* If the authenticator length is zero, there's no
584: signature to read in, so go straight to processing
585: the message. */
586: if (p -> message -> authlen == 0)
587: goto message_done;
588:
589: /* The next thing we're expecting is the
590: message signature. */
591: p -> state = omapi_protocol_signature_wait;
592:
593: /* Wait for the number of bytes specified for
594: the authenticator. If we already have it,
595: go read it in. */
596: if (omapi_connection_require
597: (c, p -> message -> authlen) == ISC_R_SUCCESS)
598: goto signature_wait;
599: break;
600: }
601:
602: /* Allocate a buffer for the name. */
603: status = (omapi_data_string_new (&p -> name, nlen, MDL));
604: if (status != ISC_R_SUCCESS) {
605: omapi_disconnect (c, 1);
606: return ISC_R_NOMEMORY;
607: }
608: p -> state = omapi_protocol_name_wait;
609: if (omapi_connection_require (c, nlen) != ISC_R_SUCCESS)
610: break;
611: /* If it's already here, fall through. */
612:
613: case omapi_protocol_name_wait:
614: omapi_connection_copyout (p -> name -> value, c,
615: p -> name -> len);
616: /* Wait for a 32-bit length. */
617: p -> state = omapi_protocol_value_length_wait;
618: if ((omapi_connection_require (c, 4)) != ISC_R_SUCCESS)
619: break;
620: /* If it's already here, fall through. */
621:
622: case omapi_protocol_value_length_wait:
623: omapi_connection_get_uint32 (c, &vlen);
624:
625: /* Zero-length values are allowed - if we get one, we
626: don't have to read any data for the value - just
627: get the next one, if there is a next one. */
628: if (!vlen)
629: goto insert_new_value;
630:
631: status = omapi_typed_data_new (MDL, &p -> value,
632: omapi_datatype_data,
633: vlen);
634: if (status != ISC_R_SUCCESS) {
635: omapi_disconnect (c, 1);
636: return ISC_R_NOMEMORY;
637: }
638:
639: p -> state = omapi_protocol_value_wait;
640: if (omapi_connection_require (c, vlen) != ISC_R_SUCCESS)
641: break;
642: /* If it's already here, fall through. */
643:
644: case omapi_protocol_value_wait:
645: omapi_connection_copyout (p -> value -> u.buffer.value, c,
646: p -> value -> u.buffer.len);
647:
648: insert_new_value:
649: if (p -> reading_message_values) {
650: status = (omapi_set_value
651: ((omapi_object_t *)p -> message,
652: p -> message -> id_object,
653: p -> name, p -> value));
654: } else {
655: if (!p -> message -> object) {
656: /* We need a generic object to hang off of the
657: incoming message. */
658: status = (omapi_generic_new
659: (&p -> message -> object, MDL));
660: if (status != ISC_R_SUCCESS) {
661: omapi_disconnect (c, 1);
662: return status;
663: }
664: }
665: status = (omapi_set_value
666: ((omapi_object_t *)p -> message -> object,
667: p -> message -> id_object,
668: p -> name, p -> value));
669: }
670: if (status != ISC_R_SUCCESS) {
671: omapi_disconnect (c, 1);
672: return status;
673: }
674: omapi_data_string_dereference (&p -> name, MDL);
675: if (p -> value)
676: omapi_typed_data_dereference (&p -> value, MDL);
677: goto need_name_length;
678:
679: signature_wait:
680: case omapi_protocol_signature_wait:
681: if (p -> message -> id_object) {
682: /* Compute the signature of the message. */
683: 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 (h);
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;
931: p -> remote_auth_list = p -> remote_auth_list -> next;
932: omapi_object_dereference (&r -> a, file, line);
933: dfree (r, file, line);
934: }
935: return ISC_R_SUCCESS;
936: }
937:
938: /* Write all the published values associated with the object through the
939: specified connection. */
940:
941: isc_result_t omapi_protocol_stuff_values (omapi_object_t *c,
942: omapi_object_t *id,
943: omapi_object_t *p)
944: {
945: if (p -> type != omapi_type_protocol)
946: return ISC_R_INVALIDARG;
947:
948: if (p -> inner && p -> inner -> type -> stuff_values)
949: return (*(p -> inner -> type -> stuff_values)) (c, id,
950: p -> inner);
951: return ISC_R_SUCCESS;
952: }
953:
954: /* Returns a boolean indicating whether this protocol requires that
955: messages be authenticated or not. */
956:
957: isc_boolean_t omapi_protocol_authenticated (omapi_object_t *h)
958: {
959: if (h -> type != omapi_type_protocol)
960: return isc_boolean_false;
961: if (((omapi_protocol_object_t *)h) -> insecure)
962: return isc_boolean_false;
963: else
964: return isc_boolean_true;
965: }
966:
967: /* Sets the address and authenticator verification callbacks. The handle
968: is to a listener object, not a protocol object. */
969:
970: isc_result_t omapi_protocol_configure_security (omapi_object_t *h,
971: isc_result_t (*verify_addr)
972: (omapi_object_t *,
973: omapi_addr_t *),
974: isc_result_t (*verify_auth)
975: (omapi_object_t *,
976: omapi_auth_key_t *))
977: {
978: omapi_protocol_listener_object_t *l;
979:
980: if (h -> outer && h -> outer -> type == omapi_type_protocol_listener)
981: h = h -> outer;
982:
983: if (h -> type != omapi_type_protocol_listener)
984: return ISC_R_INVALIDARG;
985: l = (omapi_protocol_listener_object_t *)h;
986:
987: l -> verify_auth = verify_auth;
988: l -> insecure = 0;
989:
990: return omapi_listener_configure_security (h -> outer, verify_addr);
991: }
992:
993:
994: /* Set up a listener for the omapi protocol. The handle stored points to
995: a listener object, not a protocol object. */
996:
997: isc_result_t omapi_protocol_listen (omapi_object_t *h,
998: unsigned port,
999: int max)
1000: {
1001: isc_result_t status;
1002: omapi_protocol_listener_object_t *obj;
1003:
1004: obj = (omapi_protocol_listener_object_t *)0;
1005: status = omapi_protocol_listener_allocate (&obj, MDL);
1006: if (status != ISC_R_SUCCESS)
1007: return status;
1008:
1009: status = omapi_object_reference (&h -> outer,
1010: (omapi_object_t *)obj, MDL);
1011: if (status != ISC_R_SUCCESS) {
1012: omapi_protocol_listener_dereference (&obj, MDL);
1013: return status;
1014: }
1015: status = omapi_object_reference (&obj -> inner, h, MDL);
1016: if (status != ISC_R_SUCCESS) {
1017: omapi_protocol_listener_dereference (&obj, MDL);
1018: return status;
1019: }
1020:
1021: /* What a terrible default. */
1022: obj -> insecure = 1;
1023:
1024: status = omapi_listen ((omapi_object_t *)obj, port, max);
1025: omapi_protocol_listener_dereference (&obj, MDL);
1026: return status;
1027: }
1028:
1029: /* Signal handler for protocol listener - if we get a connect signal,
1030: create a new protocol connection, otherwise pass the signal down. */
1031:
1032: isc_result_t omapi_protocol_listener_signal (omapi_object_t *o,
1033: const char *name, va_list ap)
1034: {
1035: isc_result_t status;
1036: omapi_object_t *c;
1037: omapi_protocol_object_t *obj;
1038: omapi_protocol_listener_object_t *p;
1039:
1040: if (!o || o -> type != omapi_type_protocol_listener)
1041: return ISC_R_INVALIDARG;
1042: p = (omapi_protocol_listener_object_t *)o;
1043:
1044: /* Not a signal we recognize? */
1045: if (strcmp (name, "connect")) {
1046: if (p -> inner && p -> inner -> type -> signal_handler)
1047: return (*(p -> inner -> type -> signal_handler))
1048: (p -> inner, name, ap);
1049: return ISC_R_NOTFOUND;
1050: }
1051:
1052: c = va_arg (ap, omapi_object_t *);
1053: if (!c || c -> type != omapi_type_connection)
1054: return ISC_R_INVALIDARG;
1055:
1056: obj = (omapi_protocol_object_t *)0;
1057: status = omapi_protocol_allocate (&obj, MDL);
1058: if (status != ISC_R_SUCCESS)
1059: return status;
1060:
1061: obj -> verify_auth = p -> verify_auth;
1062: obj -> insecure = p -> insecure;
1063:
1064: status = omapi_object_reference (&obj -> outer, c, MDL);
1065: if (status != ISC_R_SUCCESS) {
1066: lose:
1067: omapi_protocol_dereference (&obj, MDL);
1068: omapi_disconnect (c, 1);
1069: return status;
1070: }
1071:
1072: status = omapi_object_reference (&c -> inner,
1073: (omapi_object_t *)obj, MDL);
1074: if (status != ISC_R_SUCCESS)
1075: goto lose;
1076:
1077: /* Send the introductory message. */
1078: status = omapi_protocol_send_intro ((omapi_object_t *)obj,
1079: OMAPI_PROTOCOL_VERSION,
1080: sizeof (omapi_protocol_header_t));
1081: if (status != ISC_R_SUCCESS)
1082: goto lose;
1083:
1084: omapi_protocol_dereference (&obj, MDL);
1085: return status;
1086: }
1087:
1088: isc_result_t omapi_protocol_listener_set_value (omapi_object_t *h,
1089: omapi_object_t *id,
1090: omapi_data_string_t *name,
1091: omapi_typed_data_t *value)
1092: {
1093: if (h -> type != omapi_type_protocol_listener)
1094: return ISC_R_INVALIDARG;
1095:
1096: if (h -> inner && h -> inner -> type -> set_value)
1097: return (*(h -> inner -> type -> set_value))
1098: (h -> inner, id, name, value);
1099: return ISC_R_NOTFOUND;
1100: }
1101:
1102: isc_result_t omapi_protocol_listener_get_value (omapi_object_t *h,
1103: omapi_object_t *id,
1104: omapi_data_string_t *name,
1105: omapi_value_t **value)
1106: {
1107: if (h -> type != omapi_type_protocol_listener)
1108: return ISC_R_INVALIDARG;
1109:
1110: if (h -> inner && h -> inner -> type -> get_value)
1111: return (*(h -> inner -> type -> get_value))
1112: (h -> inner, id, name, value);
1113: return ISC_R_NOTFOUND;
1114: }
1115:
1116: isc_result_t omapi_protocol_listener_destroy (omapi_object_t *h,
1117: const char *file, int line)
1118: {
1119: if (h -> type != omapi_type_protocol_listener)
1120: return ISC_R_INVALIDARG;
1121: return ISC_R_SUCCESS;
1122: }
1123:
1124: /* Write all the published values associated with the object through the
1125: specified connection. */
1126:
1127: isc_result_t omapi_protocol_listener_stuff (omapi_object_t *c,
1128: omapi_object_t *id,
1129: omapi_object_t *p)
1130: {
1131: if (p -> type != omapi_type_protocol_listener)
1132: return ISC_R_INVALIDARG;
1133:
1134: if (p -> inner && p -> inner -> type -> stuff_values)
1135: return (*(p -> inner -> type -> stuff_values)) (c, id,
1136: p -> inner);
1137: return ISC_R_SUCCESS;
1138: }
1139:
1140: isc_result_t omapi_protocol_send_status (omapi_object_t *po,
1141: omapi_object_t *id,
1142: isc_result_t waitstatus,
1143: unsigned rid, const char *msg)
1144: {
1145: isc_result_t status;
1146: omapi_message_object_t *message = (omapi_message_object_t *)0;
1147: omapi_object_t *mo;
1148:
1149: if (po -> type != omapi_type_protocol)
1150: return ISC_R_INVALIDARG;
1151:
1152: status = omapi_message_new ((omapi_object_t **)&message, MDL);
1153: if (status != ISC_R_SUCCESS)
1154: return status;
1155: mo = (omapi_object_t *)message;
1156:
1157: status = omapi_set_int_value (mo, (omapi_object_t *)0,
1158: "op", OMAPI_OP_STATUS);
1159: if (status != ISC_R_SUCCESS) {
1160: omapi_message_dereference (&message, MDL);
1161: return status;
1162: }
1163:
1164: status = omapi_set_int_value (mo, (omapi_object_t *)0,
1165: "rid", (int)rid);
1166: if (status != ISC_R_SUCCESS) {
1167: omapi_message_dereference (&message, MDL);
1168: return status;
1169: }
1170:
1171: status = omapi_set_int_value (mo, (omapi_object_t *)0,
1172: "result", (int)waitstatus);
1173: if (status != ISC_R_SUCCESS) {
1174: omapi_message_dereference (&message, MDL);
1175: return status;
1176: }
1177:
1178: /* If a message has been provided, send it. */
1179: if (msg) {
1180: status = omapi_set_string_value (mo, (omapi_object_t *)0,
1181: "message", msg);
1182: if (status != ISC_R_SUCCESS) {
1183: omapi_message_dereference (&message, MDL);
1184: return status;
1185: }
1186: }
1187:
1188: status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0);
1189: omapi_message_dereference (&message, MDL);
1190: return status;
1191: }
1192:
1193: /* The OMAPI_NOTIFY_PROTOCOL flag will cause the notify-object for the
1194: message to be set to the protocol object. This is used when opening
1195: the default authenticator. */
1196:
1197: isc_result_t omapi_protocol_send_open (omapi_object_t *po,
1198: omapi_object_t *id,
1199: const char *type,
1200: omapi_object_t *object,
1201: unsigned flags)
1202: {
1203: isc_result_t status;
1204: omapi_message_object_t *message = (omapi_message_object_t *)0;
1205: omapi_object_t *mo;
1206:
1207: if (po -> type != omapi_type_protocol)
1208: return ISC_R_INVALIDARG;
1209:
1210: status = omapi_message_new ((omapi_object_t **)&message, MDL);
1211: mo = (omapi_object_t *)message;
1212:
1213: if (status == ISC_R_SUCCESS)
1214: status = omapi_set_int_value (mo, (omapi_object_t *)0,
1215: "op", OMAPI_OP_OPEN);
1216:
1217: if (status == ISC_R_SUCCESS)
1218: status = omapi_set_object_value (mo, (omapi_object_t *)0,
1219: "object", object);
1220:
1221: if ((flags & OMAPI_CREATE) && (status == ISC_R_SUCCESS))
1222: status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1223: "create", 1);
1224:
1225: if ((flags & OMAPI_UPDATE) && (status == ISC_R_SUCCESS))
1226: status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1227: "update", 1);
1228:
1229: if ((flags & OMAPI_EXCL) && (status == ISC_R_SUCCESS))
1230: status = omapi_set_boolean_value (mo, (omapi_object_t *)0,
1231: "exclusive", 1);
1232:
1233: if ((flags & OMAPI_NOTIFY_PROTOCOL) && (status == ISC_R_SUCCESS))
1234: status = omapi_set_object_value (mo, (omapi_object_t *)0,
1235: "notify-object", po);
1236:
1237: if (type && (status == ISC_R_SUCCESS))
1238: status = omapi_set_string_value (mo, (omapi_object_t *)0,
1239: "type", type);
1240:
1241: if (status == ISC_R_SUCCESS)
1242: status = omapi_message_register (mo);
1243:
1244: if (status == ISC_R_SUCCESS) {
1245: status = omapi_protocol_send_message (po, id, mo,
1246: (omapi_object_t *)0);
1247: if (status != ISC_R_SUCCESS)
1248: omapi_message_unregister (mo);
1249: }
1250:
1251: if (message)
1252: omapi_message_dereference (&message, MDL);
1253:
1254: return status;
1255: }
1256:
1257: isc_result_t omapi_protocol_send_update (omapi_object_t *po,
1258: omapi_object_t *id,
1259: unsigned rid,
1260: omapi_object_t *object)
1261: {
1262: isc_result_t status;
1263: omapi_message_object_t *message = (omapi_message_object_t *)0;
1264: omapi_object_t *mo;
1265:
1266: if (po -> type != omapi_type_protocol)
1267: return ISC_R_INVALIDARG;
1268:
1269: status = omapi_message_new ((omapi_object_t **)&message, MDL);
1270: if (status != ISC_R_SUCCESS)
1271: return status;
1272: mo = (omapi_object_t *)message;
1273:
1274: status = omapi_set_int_value (mo, (omapi_object_t *)0,
1275: "op", OMAPI_OP_UPDATE);
1276: if (status != ISC_R_SUCCESS) {
1277: omapi_message_dereference (&message, MDL);
1278: return status;
1279: }
1280:
1281: if (rid) {
1282: omapi_handle_t handle;
1283: status = omapi_set_int_value (mo, (omapi_object_t *)0,
1284: "rid", (int)rid);
1285: if (status != ISC_R_SUCCESS) {
1286: omapi_message_dereference (&message, MDL);
1287: return status;
1288: }
1289:
1290: status = omapi_object_handle (&handle, object);
1291: if (status != ISC_R_SUCCESS) {
1292: omapi_message_dereference (&message, MDL);
1293: return status;
1294: }
1295: status = omapi_set_int_value (mo, (omapi_object_t *)0,
1296: "handle", (int)handle);
1297: if (status != ISC_R_SUCCESS) {
1298: omapi_message_dereference (&message, MDL);
1299: return status;
1300: }
1301: }
1302:
1303: status = omapi_set_object_value (mo, (omapi_object_t *)0,
1304: "object", object);
1305: if (status != ISC_R_SUCCESS) {
1306: omapi_message_dereference (&message, MDL);
1307: return status;
1308: }
1309:
1310: status = omapi_protocol_send_message (po, id, mo, (omapi_object_t *)0);
1311: omapi_message_dereference (&message, MDL);
1312: return status;
1313: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>