isc_result_t omapi_connection_get_uint16 (omapi_object_t *c, u_int16_t *result) { u_int16_t inbuf; isc_result_t status; status = omapi_connection_copyout ((unsigned char *)&inbuf, c, sizeof inbuf); if (status != ISC_R_SUCCESS) return status; *result = ntohs (inbuf); return ISC_R_SUCCESS; }
isc_result_t omapi_protocol_signal_handler (omapi_object_t *h, const char *name, va_list ap) { isc_result_t status; omapi_protocol_object_t *p; omapi_object_t *c; omapi_message_object_t *m; omapi_value_t *signature; u_int16_t nlen; u_int32_t vlen; u_int32_t th; #if defined (DEBUG_MEMORY_LEAKAGE) unsigned long previous_outstanding = 0xDEADBEEF; unsigned long connect_outstanding = 0xDEADBEEF; #endif if (h -> type != omapi_type_protocol) { /* XXX shouldn't happen. Put an assert here? */ return ISC_R_UNEXPECTED; } p = (omapi_protocol_object_t *)h; if (!strcmp (name, "connect")) { #if defined (DEBUG_MEMORY_LEAKAGE) connect_outstanding = dmalloc_outstanding; #endif /* Send the introductory message. */ status = omapi_protocol_send_intro (h, OMAPI_PROTOCOL_VERSION, sizeof (omapi_protocol_header_t)); if (status != ISC_R_SUCCESS) { omapi_disconnect (p -> outer, 1); return status; } return ISC_R_SUCCESS; } /* Should only receive these when opening the initial authenticator. */ if (!strcmp (name, "status")) { status = va_arg (ap, isc_result_t); if (status != ISC_R_SUCCESS) { omapi_signal_in (h -> inner, "status", status, (omapi_object_t *)0); omapi_disconnect (p -> outer, 1); return status; } else { return omapi_signal_in (h -> inner, "ready"); } } /* If we get a disconnect, dump memory usage. */ if (!strcmp (name, "disconnect")) { #if defined (DEBUG_MEMORY_LEAKAGE) if (connect_outstanding != 0xDEADBEEF) { log_info ("generation %ld: %ld new, %ld outstanding, %ld%s", dmalloc_generation, dmalloc_outstanding - previous_outstanding, dmalloc_outstanding, dmalloc_longterm, " long-term"); } #endif #if defined (DEBUG_MEMORY_LEAKAGE) dmalloc_dump_outstanding (); #endif #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) dump_rc_history (); #endif for (m = omapi_registered_messages; m; m = m -> next) { if (m -> protocol_object == p) { if (m -> object) omapi_signal (m -> object, "disconnect"); } } } /* Not a signal we recognize? */ if (strcmp (name, "ready")) { if (p -> inner && p -> inner -> type -> signal_handler) return (*(p -> inner -> type -> signal_handler)) (h, name, ap); return ISC_R_NOTFOUND; } if (!p -> outer || p -> outer -> type != omapi_type_connection) return ISC_R_INVALIDARG; c = p -> outer; /* We get here because we requested that we be woken up after some number of bytes were read, and that number of bytes has in fact been read. */ switch (p -> state) { case omapi_protocol_intro_wait: /* Get protocol version and header size in network byte order. */ omapi_connection_get_uint32 (c, &p -> protocol_version); omapi_connection_get_uint32 (c, &p -> header_size); /* We currently only support the current protocol version. */ if (p -> protocol_version != OMAPI_PROTOCOL_VERSION) { omapi_disconnect (c, 1); return ISC_R_VERSIONMISMATCH; } if (p -> header_size < sizeof (omapi_protocol_header_t)) { omapi_disconnect (c, 1); return ISC_R_PROTOCOLERROR; } if (p -> default_auth) { status = omapi_protocol_send_open (h, (omapi_object_t *)0, "authenticator", p -> default_auth -> a, OMAPI_NOTIFY_PROTOCOL); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } } else { status = omapi_signal_in (h -> inner, "ready"); } to_header_wait: /* The next thing we're expecting is a message header. */ p -> state = omapi_protocol_header_wait; /* Register a need for the number of bytes in a header, and if we already have that many, process them immediately. */ if ((omapi_connection_require (c, p -> header_size)) != ISC_R_SUCCESS) break; /* If we already have the data, fall through. */ case omapi_protocol_header_wait: #if defined (DEBUG_MEMORY_LEAKAGE) if (previous_outstanding != 0xDEADBEEF) { log_info ("%s %ld: %ld new, %ld outstanding, %ld%s", "generation", dmalloc_generation, dmalloc_outstanding - previous_outstanding, dmalloc_outstanding, dmalloc_longterm, " long-term"); #endif #if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL)) dmalloc_dump_outstanding (); #endif #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) dump_rc_history (); #endif #if defined (DEBUG_MEMORY_LEAKAGE) } previous_outstanding = dmalloc_outstanding; #endif status = omapi_message_new ((omapi_object_t **)&p -> message, MDL); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } p -> verify_result = ISC_R_SUCCESS; /* Swap in the header... */ omapi_connection_get_uint32 (c, &p -> message -> authid); /* Bind the authenticator to the message object. */ if (p -> message -> authid) { status = (omapi_protocol_lookup_auth (&p -> message -> id_object, h, p -> message -> authid)); if (status != ISC_R_SUCCESS) p -> verify_result = status; /* Activate the authentication key. */ status = omapi_set_object_value (c, (omapi_object_t *)0, "input-authenticator", p -> message -> id_object); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } } omapi_connection_get_uint32 (c, &p -> message -> authlen); omapi_connection_get_uint32 (c, &p -> message -> op); omapi_connection_get_uint32 (c, &th); p -> message -> h = th; omapi_connection_get_uint32 (c, &p -> message -> id); omapi_connection_get_uint32 (c, &p -> message -> rid); /* If there was any extra header data, skip over it. */ if (p -> header_size > sizeof (omapi_protocol_header_t)) { omapi_connection_copyout (0, c, (p -> header_size - sizeof (omapi_protocol_header_t))); } /* XXX must compute partial signature across the XXX preceding bytes. Also, if authenticator specifies encryption as well as signing, we may have to decrypt the data on the way in. */ /* First we read in message-specific values, then object values. */ p -> reading_message_values = 1; need_name_length: /* The next thing we're expecting is length of the first name. */ p -> state = omapi_protocol_name_length_wait; /* Wait for a 16-bit length. */ if ((omapi_connection_require (c, 2)) != ISC_R_SUCCESS) break; /* If it's already here, fall through. */ case omapi_protocol_name_length_wait: omapi_connection_get_uint16 (c, &nlen); /* A zero-length name means that we're done reading name+value pairs. */ if (nlen == 0) { /* If we've already read in the object, we are done reading the message, but if we've just finished reading in the values associated with the message, we need to read the object. */ if (p -> reading_message_values) { p -> reading_message_values = 0; goto need_name_length; } /* If the authenticator length is zero, there's no signature to read in, so go straight to processing the message. */ if (p -> message -> authlen == 0) goto message_done; /* The next thing we're expecting is the message signature. */ p -> state = omapi_protocol_signature_wait; /* Wait for the number of bytes specified for the authenticator. If we already have it, go read it in. */ if (omapi_connection_require (c, p -> message -> authlen) == ISC_R_SUCCESS) goto signature_wait; break; } /* Allocate a buffer for the name. */ status = (omapi_data_string_new (&p -> name, nlen, MDL)); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return ISC_R_NOMEMORY; } p -> state = omapi_protocol_name_wait; if (omapi_connection_require (c, nlen) != ISC_R_SUCCESS) break; /* If it's already here, fall through. */ case omapi_protocol_name_wait: omapi_connection_copyout (p -> name -> value, c, p -> name -> len); /* Wait for a 32-bit length. */ p -> state = omapi_protocol_value_length_wait; if ((omapi_connection_require (c, 4)) != ISC_R_SUCCESS) break; /* If it's already here, fall through. */ case omapi_protocol_value_length_wait: omapi_connection_get_uint32 (c, &vlen); /* Zero-length values are allowed - if we get one, we don't have to read any data for the value - just get the next one, if there is a next one. */ if (!vlen) goto insert_new_value; status = omapi_typed_data_new (MDL, &p -> value, omapi_datatype_data, vlen); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return ISC_R_NOMEMORY; } p -> state = omapi_protocol_value_wait; if (omapi_connection_require (c, vlen) != ISC_R_SUCCESS) break; /* If it's already here, fall through. */ case omapi_protocol_value_wait: omapi_connection_copyout (p -> value -> u.buffer.value, c, p -> value -> u.buffer.len); insert_new_value: if (p -> reading_message_values) { status = (omapi_set_value ((omapi_object_t *)p -> message, p -> message -> id_object, p -> name, p -> value)); } else { if (!p -> message -> object) { /* We need a generic object to hang off of the incoming message. */ status = (omapi_generic_new (&p -> message -> object, MDL)); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } } status = (omapi_set_value ((omapi_object_t *)p -> message -> object, p -> message -> id_object, p -> name, p -> value)); } if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } omapi_data_string_dereference (&p -> name, MDL); if (p -> value) omapi_typed_data_dereference (&p -> value, MDL); goto need_name_length; signature_wait: case omapi_protocol_signature_wait: if (p -> message -> id_object) { /* Compute the signature of the message. */ signature = (omapi_value_t *)0; status = omapi_get_value_str (c, (omapi_object_t *)0, "input-signature", &signature); if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return status; } /* Disable the authentication key on the connection. */ status = omapi_set_value_str (c, (omapi_object_t *)0, "input-authenticator", (omapi_typed_data_t *)0); if (status != ISC_R_SUCCESS) { omapi_value_dereference (&signature, MDL); omapi_disconnect (c, 1); return status; } } /* Read the authenticator. */ status = omapi_typed_data_new (MDL, &p -> message -> authenticator, omapi_datatype_data, p -> message -> authlen); if (status != ISC_R_SUCCESS) { omapi_value_dereference (&signature, MDL); omapi_disconnect (c, 1); return ISC_R_NOMEMORY; } omapi_connection_copyout (p -> message -> authenticator -> u.buffer.value, c, p -> message -> authlen); /* Verify the signature. */ if (p -> message -> id_object && ((signature -> value -> u.buffer.len != p -> message -> authlen) || (memcmp (signature -> value -> u.buffer.value, p -> message -> authenticator -> u.buffer.value, p -> message -> authlen) != 0))) { /* Invalid signature. */ p -> verify_result = ISC_R_INVALIDKEY; } omapi_value_dereference (&signature, MDL); /* Process the message. */ message_done: if (p -> verify_result != ISC_R_SUCCESS) { status = omapi_protocol_send_status (h, (omapi_object_t *)0, p -> verify_result, p -> message -> id, (char *)0); } else { status = omapi_message_process ((omapi_object_t *)p -> message, h); } if (status != ISC_R_SUCCESS) { omapi_disconnect (c, 1); return ISC_R_NOMEMORY; } omapi_message_dereference (&p -> message, MDL); #if defined (DEBUG_MEMORY_LEAKAGE) log_info ("generation %ld: %ld new, %ld outstanding, %ld%s", dmalloc_generation, dmalloc_outstanding - previous_outstanding, dmalloc_outstanding, dmalloc_longterm, " long-term"); #endif #if (defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL)) dmalloc_dump_outstanding (); #endif #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) dump_rc_history (); #endif #if defined (DEBUG_MEMORY_LEAKAGE) previous_outstanding = 0xDEADBEEF; #endif /* Now wait for the next message. */ goto to_header_wait; default: /* XXX should never get here. Assertion? */ break; } return ISC_R_SUCCESS; }