1999-09-02 00:32:56 +00:00
|
|
|
/* connection.c
|
|
|
|
|
|
|
|
Subroutines for dealing with connections. */
|
|
|
|
|
|
|
|
/*
|
2020-12-14 11:28:37 -05:00
|
|
|
* Copyright (c) 2004-2020 by Internet Systems Consortium, Inc. ("ISC")
|
2005-03-17 20:15:29 +00:00
|
|
|
* Copyright (c) 1999-2003 by Internet Software Consortium
|
1999-09-02 00:32:56 +00:00
|
|
|
*
|
2017-07-12 09:23:23 -04:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
1999-09-02 00:32:56 +00:00
|
|
|
*
|
2005-03-17 20:15:29 +00:00
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
|
|
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
1999-09-02 00:32:56 +00:00
|
|
|
*
|
2005-03-17 20:15:29 +00:00
|
|
|
* Internet Systems Consortium, Inc.
|
2022-01-19 20:13:19 +01:00
|
|
|
* PO Box 360
|
|
|
|
* Newmarket, NH 03857 USA
|
2005-03-17 20:15:29 +00:00
|
|
|
* <info@isc.org>
|
2009-07-23 18:52:21 +00:00
|
|
|
* https://www.isc.org/
|
2000-03-17 04:00:32 +00:00
|
|
|
*
|
1999-09-02 00:32:56 +00:00
|
|
|
*/
|
|
|
|
|
2007-05-19 18:47:15 +00:00
|
|
|
#include "dhcpd.h"
|
2017-10-19 13:21:18 -04:00
|
|
|
#include <isc/util.h>
|
1999-10-08 03:43:15 +00:00
|
|
|
#include <omapip/omapip_p.h>
|
2000-01-25 01:26:52 +00:00
|
|
|
#include <arpa/inet.h>
|
2000-12-09 00:10:55 +00:00
|
|
|
#include <arpa/nameser.h>
|
2007-05-19 18:47:15 +00:00
|
|
|
#include <errno.h>
|
1999-09-02 00:32:56 +00:00
|
|
|
|
2001-02-15 05:38:52 +00:00
|
|
|
#if defined (TRACING)
|
|
|
|
static void trace_connect_input (trace_type_t *, unsigned, char *);
|
|
|
|
static void trace_connect_stop (trace_type_t *);
|
|
|
|
static void trace_disconnect_input (trace_type_t *, unsigned, char *);
|
|
|
|
static void trace_disconnect_stop (trace_type_t *);
|
|
|
|
trace_type_t *trace_connect;
|
|
|
|
trace_type_t *trace_disconnect;
|
|
|
|
extern omapi_array_t *trace_listeners;
|
|
|
|
#endif
|
2001-05-02 06:52:03 +00:00
|
|
|
static isc_result_t omapi_connection_connect_internal (omapi_object_t *);
|
2001-02-15 05:38:52 +00:00
|
|
|
|
2020-12-14 11:28:37 -05:00
|
|
|
static isc_result_t ctring_from_attribute(omapi_object_t *obj, char *attr_name,
|
|
|
|
char **cstr);
|
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
OMAPI_OBJECT_ALLOC (omapi_connection,
|
|
|
|
omapi_connection_object_t, omapi_type_connection)
|
|
|
|
|
1999-09-02 00:32:56 +00:00
|
|
|
isc_result_t omapi_connect (omapi_object_t *c,
|
1999-10-07 06:36:35 +00:00
|
|
|
const char *server_name,
|
1999-11-20 18:36:32 +00:00
|
|
|
unsigned port)
|
1999-09-02 00:32:56 +00:00
|
|
|
{
|
|
|
|
struct hostent *he;
|
2000-05-01 23:50:16 +00:00
|
|
|
unsigned i, hix;
|
|
|
|
omapi_addr_list_t *addrs = (omapi_addr_list_t *)0;
|
|
|
|
struct in_addr foo;
|
|
|
|
isc_result_t status;
|
|
|
|
|
2000-08-14 21:58:57 +00:00
|
|
|
#ifdef DEBUG_PROTOCOL
|
|
|
|
log_debug ("omapi_connect(%s, port=%d)", server_name, port);
|
|
|
|
#endif
|
|
|
|
|
2000-05-01 23:50:16 +00:00
|
|
|
if (!inet_aton (server_name, &foo)) {
|
|
|
|
/* If we didn't get a numeric address, try for a domain
|
|
|
|
name. It's okay for this call to block. */
|
|
|
|
he = gethostbyname (server_name);
|
|
|
|
if (!he)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_HOSTUNKNOWN;
|
2000-05-01 23:50:16 +00:00
|
|
|
for (i = 0; he -> h_addr_list [i]; i++)
|
|
|
|
;
|
|
|
|
if (i == 0)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_HOSTUNKNOWN;
|
2000-05-01 23:50:16 +00:00
|
|
|
hix = i;
|
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
status = omapi_addr_list_new (&addrs, hix, MDL);
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
return status;
|
2000-05-01 23:50:16 +00:00
|
|
|
for (i = 0; i < hix; i++) {
|
|
|
|
addrs -> addresses [i].addrtype = he -> h_addrtype;
|
|
|
|
addrs -> addresses [i].addrlen = he -> h_length;
|
|
|
|
memcpy (addrs -> addresses [i].address,
|
|
|
|
he -> h_addr_list [i],
|
|
|
|
(unsigned)he -> h_length);
|
|
|
|
addrs -> addresses [i].port = port;
|
|
|
|
}
|
|
|
|
} else {
|
2000-05-16 23:03:49 +00:00
|
|
|
status = omapi_addr_list_new (&addrs, 1, MDL);
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
return status;
|
2000-05-01 23:50:16 +00:00
|
|
|
addrs -> addresses [0].addrtype = AF_INET;
|
|
|
|
addrs -> addresses [0].addrlen = sizeof foo;
|
|
|
|
memcpy (addrs -> addresses [0].address, &foo, sizeof foo);
|
|
|
|
addrs -> addresses [0].port = port;
|
|
|
|
}
|
|
|
|
status = omapi_connect_list (c, addrs, (omapi_addr_t *)0);
|
|
|
|
omapi_addr_list_dereference (&addrs, MDL);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t omapi_connect_list (omapi_object_t *c,
|
|
|
|
omapi_addr_list_t *remote_addrs,
|
|
|
|
omapi_addr_t *local_addr)
|
|
|
|
{
|
1999-09-02 00:32:56 +00:00
|
|
|
isc_result_t status;
|
|
|
|
omapi_connection_object_t *obj;
|
1999-09-09 21:07:55 +00:00
|
|
|
int flag;
|
2000-05-01 23:50:16 +00:00
|
|
|
struct sockaddr_in local_sin;
|
1999-09-02 00:32:56 +00:00
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
obj = (omapi_connection_object_t *)0;
|
|
|
|
status = omapi_connection_allocate (&obj, MDL);
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
return status;
|
1999-09-02 00:32:56 +00:00
|
|
|
|
|
|
|
status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj,
|
2000-01-26 14:56:18 +00:00
|
|
|
MDL);
|
1999-09-02 00:32:56 +00:00
|
|
|
if (status != ISC_R_SUCCESS) {
|
2000-05-16 23:03:49 +00:00
|
|
|
omapi_connection_dereference (&obj, MDL);
|
1999-09-02 00:32:56 +00:00
|
|
|
return status;
|
|
|
|
}
|
2000-01-26 14:56:18 +00:00
|
|
|
status = omapi_object_reference (&obj -> inner, c, MDL);
|
1999-09-02 00:32:56 +00:00
|
|
|
if (status != ISC_R_SUCCESS) {
|
2000-05-16 23:03:49 +00:00
|
|
|
omapi_connection_dereference (&obj, MDL);
|
1999-09-02 00:32:56 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2001-02-12 20:49:54 +00:00
|
|
|
/* Store the address list on the object. */
|
|
|
|
omapi_addr_list_reference (&obj -> connect_list, remote_addrs, MDL);
|
|
|
|
obj -> cptr = 0;
|
|
|
|
obj -> state = omapi_connection_unconnected;
|
1999-09-09 21:07:55 +00:00
|
|
|
|
2001-02-12 20:49:54 +00:00
|
|
|
#if defined (TRACING)
|
|
|
|
/* If we're playing back, don't actually try to connect - just leave
|
|
|
|
the object available for a subsequent connect or disconnect. */
|
|
|
|
if (!trace_playback ()) {
|
|
|
|
#endif
|
|
|
|
/* Create a socket on which to communicate. */
|
|
|
|
obj -> socket =
|
|
|
|
socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
|
|
if (obj -> socket < 0) {
|
2000-05-16 23:03:49 +00:00
|
|
|
omapi_connection_dereference (&obj, MDL);
|
2001-02-12 20:49:54 +00:00
|
|
|
if (errno == EMFILE || errno == ENFILE
|
|
|
|
|| errno == ENOBUFS)
|
|
|
|
return ISC_R_NORESOURCES;
|
|
|
|
return ISC_R_UNEXPECTED;
|
2000-05-01 23:50:16 +00:00
|
|
|
}
|
2001-02-12 20:49:54 +00:00
|
|
|
|
|
|
|
/* Set up the local address, if any. */
|
|
|
|
if (local_addr) {
|
|
|
|
/* Only do TCPv4 so far. */
|
|
|
|
if (local_addr -> addrtype != AF_INET) {
|
2016-07-28 21:11:24 -07:00
|
|
|
close(obj->socket);
|
2001-02-12 20:49:54 +00:00
|
|
|
omapi_connection_dereference (&obj, MDL);
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
2001-02-12 20:49:54 +00:00
|
|
|
}
|
|
|
|
local_sin.sin_port = htons (local_addr -> port);
|
|
|
|
memcpy (&local_sin.sin_addr,
|
|
|
|
local_addr -> address,
|
|
|
|
local_addr -> addrlen);
|
2000-05-01 23:50:16 +00:00
|
|
|
#if defined (HAVE_SA_LEN)
|
2001-02-12 20:49:54 +00:00
|
|
|
local_sin.sin_len = sizeof local_addr;
|
2000-05-01 23:50:16 +00:00
|
|
|
#endif
|
2001-02-12 20:49:54 +00:00
|
|
|
local_sin.sin_family = AF_INET;
|
|
|
|
memset (&local_sin.sin_zero, 0,
|
|
|
|
sizeof local_sin.sin_zero);
|
2022-01-19 20:14:16 +01:00
|
|
|
|
2001-02-12 20:49:54 +00:00
|
|
|
if (bind (obj -> socket, (struct sockaddr *)&local_sin,
|
|
|
|
sizeof local_sin) < 0) {
|
2007-08-22 13:41:37 +00:00
|
|
|
omapi_connection_object_t **objp = &obj;
|
|
|
|
omapi_object_t **o = (omapi_object_t **)objp;
|
2016-07-28 21:11:24 -07:00
|
|
|
close(obj->socket);
|
2007-08-22 13:41:37 +00:00
|
|
|
omapi_object_dereference(o, MDL);
|
2001-02-12 20:49:54 +00:00
|
|
|
if (errno == EADDRINUSE)
|
|
|
|
return ISC_R_ADDRINUSE;
|
|
|
|
if (errno == EADDRNOTAVAIL)
|
|
|
|
return ISC_R_ADDRNOTAVAIL;
|
|
|
|
if (errno == EACCES)
|
|
|
|
return ISC_R_NOPERM;
|
|
|
|
return ISC_R_UNEXPECTED;
|
|
|
|
}
|
2001-06-27 00:31:20 +00:00
|
|
|
obj -> local_addr = local_sin;
|
2000-05-01 23:50:16 +00:00
|
|
|
}
|
|
|
|
|
2007-05-19 18:47:15 +00:00
|
|
|
#if defined(F_SETFD)
|
2001-02-12 20:49:54 +00:00
|
|
|
if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
|
|
|
|
close (obj -> socket);
|
|
|
|
omapi_connection_dereference (&obj, MDL);
|
|
|
|
return ISC_R_UNEXPECTED;
|
|
|
|
}
|
2000-01-05 18:10:59 +00:00
|
|
|
#endif
|
|
|
|
|
2001-02-12 20:49:54 +00:00
|
|
|
/* Set the SO_REUSEADDR flag (this should not fail). */
|
|
|
|
flag = 1;
|
|
|
|
if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
|
|
|
|
(char *)&flag, sizeof flag) < 0) {
|
|
|
|
omapi_connection_dereference (&obj, MDL);
|
|
|
|
return ISC_R_UNEXPECTED;
|
|
|
|
}
|
2022-01-19 20:14:16 +01:00
|
|
|
|
2001-02-12 20:49:54 +00:00
|
|
|
/* Set the file to nonblocking mode. */
|
|
|
|
if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
|
|
|
|
omapi_connection_dereference (&obj, MDL);
|
|
|
|
return ISC_R_UNEXPECTED;
|
|
|
|
}
|
1999-09-02 00:32:56 +00:00
|
|
|
|
2010-11-18 19:47:36 +00:00
|
|
|
#ifdef SO_NOSIGPIPE
|
|
|
|
/*
|
|
|
|
* If available stop the OS from killing our
|
|
|
|
* program on a SIGPIPE failure
|
|
|
|
*/
|
|
|
|
flag = 1;
|
|
|
|
if (setsockopt(obj->socket, SOL_SOCKET, SO_NOSIGPIPE,
|
|
|
|
(char *)&flag, sizeof(flag)) < 0) {
|
|
|
|
omapi_connection_dereference (&obj, MDL);
|
|
|
|
return ISC_R_UNEXPECTED;
|
2022-01-19 20:14:16 +01:00
|
|
|
}
|
2010-11-18 19:47:36 +00:00
|
|
|
#endif
|
|
|
|
|
2001-02-12 20:49:54 +00:00
|
|
|
status = (omapi_register_io_object
|
|
|
|
((omapi_object_t *)obj,
|
|
|
|
0, omapi_connection_writefd,
|
|
|
|
0, omapi_connection_connect,
|
|
|
|
omapi_connection_reaper));
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
goto out;
|
2001-05-02 06:52:03 +00:00
|
|
|
status = omapi_connection_connect_internal ((omapi_object_t *)
|
|
|
|
obj);
|
2011-05-24 00:36:58 +00:00
|
|
|
/*
|
|
|
|
* inprogress is the same as success but used
|
|
|
|
* to indicate to the dispatch code that we should
|
|
|
|
* mark the socket as requiring more attention.
|
|
|
|
* Routines calling this function should handle
|
|
|
|
* success properly.
|
|
|
|
*/
|
|
|
|
if (status == ISC_R_INPROGRESS) {
|
|
|
|
status = ISC_R_SUCCESS;
|
|
|
|
}
|
2001-02-12 20:49:54 +00:00
|
|
|
#if defined (TRACING)
|
|
|
|
}
|
|
|
|
omapi_connection_register (obj, MDL);
|
|
|
|
#endif
|
1999-09-02 00:32:56 +00:00
|
|
|
|
2000-09-29 20:58:26 +00:00
|
|
|
out:
|
2000-05-16 23:03:49 +00:00
|
|
|
omapi_connection_dereference (&obj, MDL);
|
2000-05-01 23:50:16 +00:00
|
|
|
return status;
|
1999-09-02 00:32:56 +00:00
|
|
|
}
|
|
|
|
|
2001-02-12 20:49:54 +00:00
|
|
|
#if defined (TRACING)
|
2001-02-15 05:38:52 +00:00
|
|
|
omapi_array_t *omapi_connections;
|
2001-02-12 20:49:54 +00:00
|
|
|
|
2001-02-17 21:34:56 +00:00
|
|
|
OMAPI_ARRAY_TYPE(omapi_connection, omapi_connection_object_t)
|
2001-02-12 20:49:54 +00:00
|
|
|
|
2001-02-15 05:38:52 +00:00
|
|
|
void omapi_connection_trace_setup (void) {
|
|
|
|
trace_connect = trace_type_register ("connect", (void *)0,
|
|
|
|
trace_connect_input,
|
|
|
|
trace_connect_stop, MDL);
|
|
|
|
trace_disconnect = trace_type_register ("disconnect", (void *)0,
|
|
|
|
trace_disconnect_input,
|
|
|
|
trace_disconnect_stop, MDL);
|
|
|
|
}
|
|
|
|
|
2001-02-12 20:49:54 +00:00
|
|
|
void omapi_connection_register (omapi_connection_object_t *obj,
|
|
|
|
const char *file, int line)
|
|
|
|
{
|
|
|
|
isc_result_t status;
|
2001-02-15 05:38:52 +00:00
|
|
|
trace_iov_t iov [6];
|
|
|
|
int iov_count = 0;
|
|
|
|
int32_t connect_index, listener_index;
|
|
|
|
static int32_t index;
|
2001-02-12 20:49:54 +00:00
|
|
|
|
|
|
|
if (!omapi_connections) {
|
|
|
|
status = omapi_connection_array_allocate (&omapi_connections,
|
|
|
|
file, line);
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-02-15 05:38:52 +00:00
|
|
|
status = omapi_connection_array_extend (omapi_connections, obj,
|
2001-02-15 20:31:36 +00:00
|
|
|
(int *)0, file, line);
|
2001-02-15 05:38:52 +00:00
|
|
|
if (status != ISC_R_SUCCESS) {
|
|
|
|
obj -> index = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-05-17 19:04:09 +00:00
|
|
|
#if defined (TRACING)
|
2001-02-15 05:38:52 +00:00
|
|
|
if (trace_record ()) {
|
|
|
|
/* Connection registration packet:
|
2022-01-19 20:14:16 +01:00
|
|
|
|
2001-02-15 05:38:52 +00:00
|
|
|
int32_t index
|
|
|
|
int32_t listener_index [-1 means no listener]
|
|
|
|
u_int16_t remote_port
|
|
|
|
u_int16_t local_port
|
|
|
|
u_int32_t remote_addr
|
|
|
|
u_int32_t local_addr */
|
|
|
|
|
|
|
|
connect_index = htonl (index);
|
|
|
|
index++;
|
|
|
|
if (obj -> listener)
|
|
|
|
listener_index = htonl (obj -> listener -> index);
|
|
|
|
else
|
|
|
|
listener_index = htonl (-1);
|
|
|
|
iov [iov_count].buf = (char *)&connect_index;
|
|
|
|
iov [iov_count++].len = sizeof connect_index;
|
|
|
|
iov [iov_count].buf = (char *)&listener_index;
|
|
|
|
iov [iov_count++].len = sizeof listener_index;
|
|
|
|
iov [iov_count].buf = (char *)&obj -> remote_addr.sin_port;
|
|
|
|
iov [iov_count++].len = sizeof obj -> remote_addr.sin_port;
|
|
|
|
iov [iov_count].buf = (char *)&obj -> local_addr.sin_port;
|
|
|
|
iov [iov_count++].len = sizeof obj -> local_addr.sin_port;
|
|
|
|
iov [iov_count].buf = (char *)&obj -> remote_addr.sin_addr;
|
|
|
|
iov [iov_count++].len = sizeof obj -> remote_addr.sin_addr;
|
|
|
|
iov [iov_count].buf = (char *)&obj -> local_addr.sin_addr;
|
|
|
|
iov [iov_count++].len = sizeof obj -> local_addr.sin_addr;
|
|
|
|
|
|
|
|
status = trace_write_packet_iov (trace_connect,
|
|
|
|
iov_count, iov, file, line);
|
|
|
|
}
|
2001-05-17 19:04:09 +00:00
|
|
|
#endif
|
2001-02-12 20:49:54 +00:00
|
|
|
}
|
2001-02-15 05:38:52 +00:00
|
|
|
|
|
|
|
static void trace_connect_input (trace_type_t *ttype,
|
|
|
|
unsigned length, char *buf)
|
|
|
|
{
|
|
|
|
struct sockaddr_in remote, local;
|
|
|
|
int32_t connect_index, listener_index;
|
|
|
|
char *s = buf;
|
|
|
|
omapi_connection_object_t *obj;
|
|
|
|
isc_result_t status;
|
2001-06-27 00:31:20 +00:00
|
|
|
int i;
|
2001-02-15 05:38:52 +00:00
|
|
|
|
|
|
|
if (length != ((sizeof connect_index) +
|
|
|
|
(sizeof remote.sin_port) +
|
|
|
|
(sizeof remote.sin_addr)) * 2) {
|
|
|
|
log_error ("Trace connect: invalid length %d", length);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset (&remote, 0, sizeof remote);
|
|
|
|
memset (&local, 0, sizeof local);
|
2001-06-27 00:31:20 +00:00
|
|
|
memcpy (&connect_index, s, sizeof connect_index);
|
2001-02-15 05:38:52 +00:00
|
|
|
s += sizeof connect_index;
|
2001-06-27 00:31:20 +00:00
|
|
|
memcpy (&listener_index, s, sizeof listener_index);
|
2001-02-15 05:38:52 +00:00
|
|
|
s += sizeof listener_index;
|
|
|
|
memcpy (&remote.sin_port, s, sizeof remote.sin_port);
|
|
|
|
s += sizeof remote.sin_port;
|
|
|
|
memcpy (&local.sin_port, s, sizeof local.sin_port);
|
|
|
|
s += sizeof local.sin_port;
|
|
|
|
memcpy (&remote.sin_addr, s, sizeof remote.sin_addr);
|
|
|
|
s += sizeof remote.sin_addr;
|
|
|
|
memcpy (&local.sin_addr, s, sizeof local.sin_addr);
|
|
|
|
s += sizeof local.sin_addr;
|
2013-05-15 10:49:54 +10:00
|
|
|
POST(s);
|
2001-02-15 05:38:52 +00:00
|
|
|
|
|
|
|
connect_index = ntohl (connect_index);
|
|
|
|
listener_index = ntohl (listener_index);
|
|
|
|
|
|
|
|
/* If this was a connect to a listener, then we just slap together
|
|
|
|
a new connection. */
|
|
|
|
if (listener_index != -1) {
|
|
|
|
omapi_listener_object_t *listener;
|
|
|
|
listener = (omapi_listener_object_t *)0;
|
|
|
|
omapi_array_foreach_begin (trace_listeners,
|
|
|
|
omapi_listener_object_t, lp) {
|
|
|
|
if (lp -> address.sin_port == local.sin_port) {
|
|
|
|
omapi_listener_reference (&listener, lp, MDL);
|
|
|
|
omapi_listener_dereference (&lp, MDL);
|
|
|
|
break;
|
2022-01-19 20:14:16 +01:00
|
|
|
}
|
2001-02-15 05:38:52 +00:00
|
|
|
} omapi_array_foreach_end (trace_listeners,
|
|
|
|
omapi_listener_object_t, lp);
|
|
|
|
if (!listener) {
|
2001-02-15 20:35:40 +00:00
|
|
|
log_error ("%s%ld, addr %s, port %d",
|
2001-02-15 05:38:52 +00:00
|
|
|
"Spurious traced listener connect - index ",
|
2001-02-15 20:35:40 +00:00
|
|
|
(long int)listener_index,
|
|
|
|
inet_ntoa (local.sin_addr),
|
2001-02-15 05:38:52 +00:00
|
|
|
ntohs (local.sin_port));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
obj = (omapi_connection_object_t *)0;
|
|
|
|
status = omapi_listener_connect (&obj, listener, -1, &remote);
|
|
|
|
if (status != ISC_R_SUCCESS) {
|
|
|
|
log_error ("traced listener connect: %s",
|
|
|
|
isc_result_totext (status));
|
|
|
|
}
|
|
|
|
if (obj)
|
|
|
|
omapi_connection_dereference (&obj, MDL);
|
|
|
|
omapi_listener_dereference (&listener, MDL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find the matching connect object, if there is one. */
|
|
|
|
omapi_array_foreach_begin (omapi_connections,
|
|
|
|
omapi_connection_object_t, lp) {
|
2012-10-16 15:05:24 -07:00
|
|
|
for (i = 0; (lp->connect_list &&
|
|
|
|
i < lp->connect_list->count); i++) {
|
2001-06-27 00:31:20 +00:00
|
|
|
if (!memcmp (&remote.sin_addr,
|
2012-10-16 15:05:24 -07:00
|
|
|
&lp->connect_list->addresses[i].address,
|
2001-06-27 00:31:20 +00:00
|
|
|
sizeof remote.sin_addr) &&
|
|
|
|
(ntohs (remote.sin_port) ==
|
2012-10-16 15:05:24 -07:00
|
|
|
lp->connect_list->addresses[i].port)) {
|
|
|
|
lp->state = omapi_connection_connected;
|
|
|
|
lp->remote_addr = remote;
|
|
|
|
lp->remote_addr.sin_family = AF_INET;
|
|
|
|
omapi_addr_list_dereference(&lp->connect_list, MDL);
|
|
|
|
lp->index = connect_index;
|
|
|
|
status = omapi_signal_in((omapi_object_t *)lp,
|
|
|
|
"connect");
|
|
|
|
omapi_connection_dereference (&lp, MDL);
|
|
|
|
return;
|
|
|
|
}
|
2001-02-15 05:38:52 +00:00
|
|
|
}
|
|
|
|
} omapi_array_foreach_end (omapi_connections,
|
|
|
|
omapi_connection_object_t, lp);
|
2022-01-19 20:14:16 +01:00
|
|
|
|
2001-02-15 20:35:40 +00:00
|
|
|
log_error ("Spurious traced connect - index %ld, addr %s, port %d",
|
|
|
|
(long int)connect_index, inet_ntoa (remote.sin_addr),
|
2001-02-15 05:38:52 +00:00
|
|
|
ntohs (remote.sin_port));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void trace_connect_stop (trace_type_t *ttype) { }
|
|
|
|
|
|
|
|
static void trace_disconnect_input (trace_type_t *ttype,
|
|
|
|
unsigned length, char *buf)
|
|
|
|
{
|
|
|
|
int32_t *index;
|
|
|
|
if (length != sizeof *index) {
|
|
|
|
log_error ("trace disconnect: wrong length %d", length);
|
|
|
|
return;
|
|
|
|
}
|
2022-01-19 20:14:16 +01:00
|
|
|
|
2001-02-15 05:38:52 +00:00
|
|
|
index = (int32_t *)buf;
|
|
|
|
|
|
|
|
omapi_array_foreach_begin (omapi_connections,
|
|
|
|
omapi_connection_object_t, lp) {
|
|
|
|
if (lp -> index == ntohl (*index)) {
|
|
|
|
omapi_disconnect ((omapi_object_t *)lp, 1);
|
|
|
|
omapi_connection_dereference (&lp, MDL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} omapi_array_foreach_end (omapi_connections,
|
|
|
|
omapi_connection_object_t, lp);
|
|
|
|
|
2001-02-15 20:35:40 +00:00
|
|
|
log_error ("trace disconnect: no connection matching index %ld",
|
|
|
|
(long int)ntohl (*index));
|
2001-02-15 05:38:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void trace_disconnect_stop (trace_type_t *ttype) { }
|
2001-02-12 20:49:54 +00:00
|
|
|
#endif
|
|
|
|
|
1999-09-02 00:32:56 +00:00
|
|
|
/* Disconnect a connection object from the remote end. If force is nonzero,
|
|
|
|
close the connection immediately. Otherwise, shut down the receiving end
|
|
|
|
but allow any unsent data to be sent before actually closing the socket. */
|
|
|
|
|
|
|
|
isc_result_t omapi_disconnect (omapi_object_t *h,
|
|
|
|
int force)
|
|
|
|
{
|
|
|
|
omapi_connection_object_t *c;
|
|
|
|
|
2000-08-14 21:58:57 +00:00
|
|
|
#ifdef DEBUG_PROTOCOL
|
2020-01-23 16:21:52 -05:00
|
|
|
log_debug ("omapi_disconnect(force=%d)", force);
|
2000-08-14 21:58:57 +00:00
|
|
|
#endif
|
|
|
|
|
1999-09-02 00:32:56 +00:00
|
|
|
c = (omapi_connection_object_t *)h;
|
|
|
|
if (c -> type != omapi_type_connection)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
1999-09-02 00:32:56 +00:00
|
|
|
|
2001-02-15 05:38:52 +00:00
|
|
|
#if defined (TRACING)
|
|
|
|
if (trace_record ()) {
|
2008-02-28 21:21:56 +00:00
|
|
|
isc_result_t status;
|
2001-02-15 05:38:52 +00:00
|
|
|
int32_t index;
|
|
|
|
|
|
|
|
index = htonl (c -> index);
|
|
|
|
status = trace_write_packet (trace_disconnect,
|
|
|
|
sizeof index, (char *)&index,
|
|
|
|
MDL);
|
|
|
|
if (status != ISC_R_SUCCESS) {
|
|
|
|
trace_stop ();
|
|
|
|
log_error ("trace_write_packet: %s",
|
|
|
|
isc_result_totext (status));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!trace_playback ()) {
|
|
|
|
#endif
|
|
|
|
if (!force) {
|
|
|
|
/* If we're already disconnecting, we don't have to do
|
|
|
|
anything. */
|
|
|
|
if (c -> state == omapi_connection_disconnecting)
|
1999-09-02 00:32:56 +00:00
|
|
|
return ISC_R_SUCCESS;
|
2001-02-15 05:38:52 +00:00
|
|
|
|
|
|
|
/* Try to shut down the socket - this sends a FIN to
|
|
|
|
the remote end, so that it won't send us any more
|
|
|
|
data. If the shutdown succeeds, and we still
|
|
|
|
have bytes left to write, defer closing the socket
|
|
|
|
until that's done. */
|
|
|
|
if (!shutdown (c -> socket, SHUT_RD)) {
|
|
|
|
if (c -> out_bytes > 0) {
|
|
|
|
c -> state =
|
|
|
|
omapi_connection_disconnecting;
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
1999-09-02 00:32:56 +00:00
|
|
|
}
|
|
|
|
}
|
2001-02-15 05:38:52 +00:00
|
|
|
close (c -> socket);
|
|
|
|
#if defined (TRACING)
|
1999-09-02 00:32:56 +00:00
|
|
|
}
|
2001-02-15 05:38:52 +00:00
|
|
|
#endif
|
1999-09-02 00:32:56 +00:00
|
|
|
c -> state = omapi_connection_closed;
|
|
|
|
|
2009-10-28 04:12:30 +00:00
|
|
|
#if 0
|
|
|
|
/*
|
|
|
|
* Disconnecting from the I/O object seems incorrect as it doesn't
|
|
|
|
* cause the I/O object to be cleaned and released. Previous to
|
|
|
|
* using the isc socket library this wouldn't have caused a problem
|
|
|
|
* with the socket library we would have a reference to a closed
|
|
|
|
* socket. Instead we now do an unregister to properly free the
|
|
|
|
* I/O object.
|
|
|
|
*/
|
|
|
|
|
1999-09-02 00:32:56 +00:00
|
|
|
/* Disconnect from I/O object, if any. */
|
2000-06-06 23:47:14 +00:00
|
|
|
if (h -> outer) {
|
|
|
|
if (h -> outer -> inner)
|
|
|
|
omapi_object_dereference (&h -> outer -> inner, MDL);
|
2000-01-26 14:56:18 +00:00
|
|
|
omapi_object_dereference (&h -> outer, MDL);
|
2000-06-06 23:47:14 +00:00
|
|
|
}
|
2009-10-28 04:12:30 +00:00
|
|
|
#else
|
|
|
|
if (h->outer) {
|
|
|
|
omapi_unregister_io_object(h);
|
|
|
|
}
|
|
|
|
#endif
|
1999-09-02 00:32:56 +00:00
|
|
|
|
|
|
|
/* If whatever created us registered a signal handler, send it
|
|
|
|
a disconnect signal. */
|
|
|
|
omapi_signal (h, "disconnect", h);
|
2008-03-18 18:28:14 +00:00
|
|
|
|
|
|
|
/* Disconnect from protocol object, if any. */
|
|
|
|
if (h->inner != NULL) {
|
|
|
|
if (h->inner->outer != NULL) {
|
|
|
|
omapi_object_dereference(&h->inner->outer, MDL);
|
|
|
|
}
|
|
|
|
omapi_object_dereference(&h->inner, MDL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: the code to free buffers should be in the dereference
|
|
|
|
function, but there is no special-purpose function to
|
|
|
|
dereference connections, so these just get leaked */
|
|
|
|
/* Free any buffers */
|
|
|
|
if (c->inbufs != NULL) {
|
|
|
|
omapi_buffer_dereference(&c->inbufs, MDL);
|
|
|
|
}
|
|
|
|
c->in_bytes = 0;
|
|
|
|
if (c->outbufs != NULL) {
|
|
|
|
omapi_buffer_dereference(&c->outbufs, MDL);
|
|
|
|
}
|
|
|
|
c->out_bytes = 0;
|
|
|
|
|
1999-09-02 00:32:56 +00:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
1999-10-07 06:36:35 +00:00
|
|
|
isc_result_t omapi_connection_require (omapi_object_t *h, unsigned bytes)
|
1999-09-02 00:32:56 +00:00
|
|
|
{
|
|
|
|
omapi_connection_object_t *c;
|
|
|
|
|
|
|
|
if (h -> type != omapi_type_connection)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
1999-09-02 00:32:56 +00:00
|
|
|
c = (omapi_connection_object_t *)h;
|
|
|
|
|
|
|
|
c -> bytes_needed = bytes;
|
|
|
|
if (c -> bytes_needed <= c -> in_bytes) {
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_NOTYET;
|
1999-09-02 00:32:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the socket on which the dispatcher should wait for readiness
|
2009-10-28 04:12:30 +00:00
|
|
|
to read, for a connection object. */
|
1999-09-02 00:32:56 +00:00
|
|
|
int omapi_connection_readfd (omapi_object_t *h)
|
|
|
|
{
|
|
|
|
omapi_connection_object_t *c;
|
|
|
|
if (h -> type != omapi_type_connection)
|
|
|
|
return -1;
|
|
|
|
c = (omapi_connection_object_t *)h;
|
|
|
|
if (c -> state != omapi_connection_connected)
|
|
|
|
return -1;
|
|
|
|
return c -> socket;
|
|
|
|
}
|
|
|
|
|
2009-10-28 04:12:30 +00:00
|
|
|
/*
|
|
|
|
* Return the socket on which the dispatcher should wait for readiness
|
|
|
|
* to write, for a connection object. When bytes are buffered we should
|
|
|
|
* also poke the dispatcher to tell it to start or re-start watching the
|
|
|
|
* socket.
|
|
|
|
*/
|
1999-09-02 00:32:56 +00:00
|
|
|
int omapi_connection_writefd (omapi_object_t *h)
|
|
|
|
{
|
|
|
|
omapi_connection_object_t *c;
|
|
|
|
if (h -> type != omapi_type_connection)
|
|
|
|
return -1;
|
1999-09-09 21:07:55 +00:00
|
|
|
c = (omapi_connection_object_t *)h;
|
2009-10-28 04:12:30 +00:00
|
|
|
return c->socket;
|
1999-09-02 00:32:56 +00:00
|
|
|
}
|
|
|
|
|
2000-05-01 23:50:16 +00:00
|
|
|
isc_result_t omapi_connection_connect (omapi_object_t *h)
|
2001-05-02 06:52:03 +00:00
|
|
|
{
|
|
|
|
isc_result_t status;
|
|
|
|
|
2009-11-19 23:49:57 +00:00
|
|
|
/*
|
2010-12-14 21:59:44 +00:00
|
|
|
* We use the INPROGRESS status to indicate that
|
|
|
|
* we want more from the socket. In this case we
|
|
|
|
* have now connected and are trying to write to
|
|
|
|
* the socket for the first time. For the signaling
|
|
|
|
* code this is the same as a SUCCESS so we don't
|
|
|
|
* pass it on as a signal.
|
2009-11-19 23:49:57 +00:00
|
|
|
*/
|
2010-12-14 21:59:44 +00:00
|
|
|
status = omapi_connection_connect_internal (h);
|
2022-01-19 20:14:16 +01:00
|
|
|
if (status == ISC_R_INPROGRESS)
|
2009-11-19 23:49:57 +00:00
|
|
|
return ISC_R_INPROGRESS;
|
|
|
|
|
2010-12-14 21:59:44 +00:00
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
omapi_signal (h, "status", status);
|
|
|
|
|
2001-05-02 06:52:03 +00:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t omapi_connection_connect_internal (omapi_object_t *h)
|
2000-05-01 23:50:16 +00:00
|
|
|
{
|
2012-10-16 15:05:24 -07:00
|
|
|
int error = 0;
|
2000-05-01 23:50:16 +00:00
|
|
|
omapi_connection_object_t *c;
|
2007-05-19 18:47:15 +00:00
|
|
|
socklen_t sl;
|
2000-05-01 23:50:16 +00:00
|
|
|
isc_result_t status;
|
|
|
|
|
|
|
|
if (h -> type != omapi_type_connection)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
2000-05-01 23:50:16 +00:00
|
|
|
c = (omapi_connection_object_t *)h;
|
|
|
|
|
|
|
|
if (c -> state == omapi_connection_connecting) {
|
|
|
|
sl = sizeof error;
|
|
|
|
if (getsockopt (c -> socket, SOL_SOCKET, SO_ERROR,
|
2000-05-17 16:04:26 +00:00
|
|
|
(char *)&error, &sl) < 0) {
|
2000-05-01 23:50:16 +00:00
|
|
|
omapi_disconnect (h, 1);
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
2000-05-03 06:12:28 +00:00
|
|
|
if (!error)
|
2000-05-01 23:50:16 +00:00
|
|
|
c -> state = omapi_connection_connected;
|
|
|
|
}
|
|
|
|
if (c -> state == omapi_connection_connecting ||
|
|
|
|
c -> state == omapi_connection_unconnected) {
|
|
|
|
if (c -> cptr >= c -> connect_list -> count) {
|
2001-05-02 06:52:03 +00:00
|
|
|
switch (error) {
|
|
|
|
case ECONNREFUSED:
|
|
|
|
status = ISC_R_CONNREFUSED;
|
|
|
|
break;
|
|
|
|
case ENETUNREACH:
|
|
|
|
status = ISC_R_NETUNREACH;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
status = uerr2isc (error);
|
|
|
|
break;
|
|
|
|
}
|
2000-05-01 23:50:16 +00:00
|
|
|
omapi_disconnect (h, 1);
|
2001-05-02 06:52:03 +00:00
|
|
|
return status;
|
2000-05-01 23:50:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (c -> connect_list -> addresses [c -> cptr].addrtype !=
|
|
|
|
AF_INET) {
|
|
|
|
omapi_disconnect (h, 1);
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
2000-05-01 23:50:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
memcpy (&c -> remote_addr.sin_addr,
|
|
|
|
&c -> connect_list -> addresses [c -> cptr].address,
|
|
|
|
sizeof c -> remote_addr.sin_addr);
|
|
|
|
c -> remote_addr.sin_family = AF_INET;
|
|
|
|
c -> remote_addr.sin_port =
|
|
|
|
htons (c -> connect_list -> addresses [c -> cptr].port);
|
|
|
|
#if defined (HAVE_SA_LEN)
|
|
|
|
c -> remote_addr.sin_len = sizeof c -> remote_addr;
|
|
|
|
#endif
|
|
|
|
memset (&c -> remote_addr.sin_zero, 0,
|
|
|
|
sizeof c -> remote_addr.sin_zero);
|
|
|
|
++c -> cptr;
|
|
|
|
|
2000-05-03 06:12:28 +00:00
|
|
|
error = connect (c -> socket,
|
|
|
|
(struct sockaddr *)&c -> remote_addr,
|
|
|
|
sizeof c -> remote_addr);
|
|
|
|
if (error < 0) {
|
|
|
|
error = errno;
|
|
|
|
if (error != EINPROGRESS) {
|
2000-05-01 23:50:16 +00:00
|
|
|
omapi_disconnect (h, 1);
|
2000-09-29 20:58:26 +00:00
|
|
|
switch (error) {
|
|
|
|
case ECONNREFUSED:
|
|
|
|
status = ISC_R_CONNREFUSED;
|
|
|
|
break;
|
|
|
|
case ENETUNREACH:
|
|
|
|
status = ISC_R_NETUNREACH;
|
|
|
|
break;
|
|
|
|
default:
|
2001-05-02 06:52:03 +00:00
|
|
|
status = uerr2isc (error);
|
2000-09-29 20:58:26 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return status;
|
2000-05-01 23:50:16 +00:00
|
|
|
}
|
|
|
|
c -> state = omapi_connection_connecting;
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INCOMPLETE;
|
2000-05-01 23:50:16 +00:00
|
|
|
}
|
|
|
|
c -> state = omapi_connection_connected;
|
|
|
|
}
|
2022-01-19 20:14:16 +01:00
|
|
|
|
2000-05-01 23:50:16 +00:00
|
|
|
/* I don't know why this would fail, so I'm tempted not to test
|
|
|
|
the return value. */
|
|
|
|
sl = sizeof (c -> local_addr);
|
|
|
|
if (getsockname (c -> socket,
|
|
|
|
(struct sockaddr *)&c -> local_addr, &sl) < 0) {
|
|
|
|
}
|
|
|
|
|
2009-10-15 18:39:49 +00:00
|
|
|
/* Reregister with the I/O object. If we don't already have an
|
|
|
|
I/O object this turns into a register call, otherwise we simply
|
|
|
|
modify the pointers in the I/O object. */
|
|
|
|
|
|
|
|
status = omapi_reregister_io_object (h,
|
|
|
|
omapi_connection_readfd,
|
|
|
|
omapi_connection_writefd,
|
|
|
|
omapi_connection_reader,
|
|
|
|
omapi_connection_writer,
|
|
|
|
omapi_connection_reaper);
|
2000-05-01 23:50:16 +00:00
|
|
|
|
|
|
|
if (status != ISC_R_SUCCESS) {
|
|
|
|
omapi_disconnect (h, 1);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
omapi_signal_in (h, "connect");
|
|
|
|
omapi_addr_list_dereference (&c -> connect_list, MDL);
|
2009-11-19 23:49:57 +00:00
|
|
|
return ISC_R_INPROGRESS;
|
2000-05-01 23:50:16 +00:00
|
|
|
}
|
|
|
|
|
1999-09-02 00:32:56 +00:00
|
|
|
/* Reaper function for connection - if the connection is completely closed,
|
|
|
|
reap it. If it's in the disconnecting state, there were bytes left
|
|
|
|
to write when the user closed it, so if there are now no bytes left to
|
|
|
|
write, we can close it. */
|
|
|
|
isc_result_t omapi_connection_reaper (omapi_object_t *h)
|
|
|
|
{
|
|
|
|
omapi_connection_object_t *c;
|
|
|
|
|
|
|
|
if (h -> type != omapi_type_connection)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
1999-09-02 00:32:56 +00:00
|
|
|
|
|
|
|
c = (omapi_connection_object_t *)h;
|
|
|
|
if (c -> state == omapi_connection_disconnecting &&
|
2000-08-14 21:58:57 +00:00
|
|
|
c -> out_bytes == 0) {
|
|
|
|
#ifdef DEBUG_PROTOCOL
|
|
|
|
log_debug ("omapi_connection_reaper(): disconnect");
|
|
|
|
#endif
|
1999-09-02 00:32:56 +00:00
|
|
|
omapi_disconnect (h, 1);
|
2000-08-14 21:58:57 +00:00
|
|
|
}
|
|
|
|
if (c -> state == omapi_connection_closed) {
|
|
|
|
#ifdef DEBUG_PROTOCOL
|
|
|
|
log_debug ("omapi_connection_reaper(): closed");
|
|
|
|
#endif
|
1999-09-02 00:32:56 +00:00
|
|
|
return ISC_R_NOTCONNECTED;
|
2000-08-14 21:58:57 +00:00
|
|
|
}
|
1999-09-02 00:32:56 +00:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2009-10-28 04:12:30 +00:00
|
|
|
static isc_result_t make_dst_key (dst_key_t **dst_key, omapi_object_t *a) {
|
2020-12-14 11:28:37 -05:00
|
|
|
omapi_value_t *key = 0;
|
|
|
|
char *name_str = 0;
|
|
|
|
char *algorithm_str = 0;
|
2000-08-03 21:00:41 +00:00
|
|
|
isc_result_t status = ISC_R_SUCCESS;
|
|
|
|
|
2020-12-14 11:28:37 -05:00
|
|
|
/* Get the key name as a C string. */
|
|
|
|
status = ctring_from_attribute(a, "name", &name_str);
|
2000-08-03 21:00:41 +00:00
|
|
|
if (status == ISC_R_SUCCESS) {
|
2020-12-14 11:28:37 -05:00
|
|
|
/* Get the algorithm name as a C string. */
|
|
|
|
status = ctring_from_attribute(a, "algorithm", &algorithm_str);
|
|
|
|
if (status == ISC_R_SUCCESS) {
|
|
|
|
/* Get the key secret value */
|
|
|
|
status = omapi_get_value_str(a, 0, "key", &key);
|
|
|
|
if (status == ISC_R_SUCCESS) {
|
|
|
|
/* Now let's try and create the key */
|
|
|
|
status = isclib_make_dst_key(
|
|
|
|
name_str,
|
|
|
|
algorithm_str,
|
|
|
|
key->value->u.buffer.value,
|
|
|
|
key->value->u.buffer.len,
|
|
|
|
dst_key);
|
|
|
|
|
|
|
|
if (*dst_key == NULL) {
|
|
|
|
status = ISC_R_NOMEMORY;
|
|
|
|
}
|
|
|
|
}
|
2000-08-03 21:00:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name_str)
|
|
|
|
dfree (name_str, MDL);
|
2020-12-14 11:28:37 -05:00
|
|
|
if (algorithm_str)
|
|
|
|
dfree (algorithm_str, MDL);
|
2000-08-03 21:00:41 +00:00
|
|
|
if (key)
|
|
|
|
omapi_value_dereference (&key, MDL);
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t omapi_connection_sign_data (int mode,
|
2009-10-28 04:12:30 +00:00
|
|
|
dst_key_t *key,
|
2000-08-03 21:00:41 +00:00
|
|
|
void **context,
|
2000-08-17 19:43:04 +00:00
|
|
|
const unsigned char *data,
|
2000-08-03 21:00:41 +00:00
|
|
|
const unsigned len,
|
|
|
|
omapi_typed_data_t **result)
|
|
|
|
{
|
|
|
|
omapi_typed_data_t *td = (omapi_typed_data_t *)0;
|
|
|
|
isc_result_t status;
|
2009-10-28 04:12:30 +00:00
|
|
|
dst_context_t **dctx = (dst_context_t **)context;
|
2000-08-03 21:00:41 +00:00
|
|
|
|
2009-10-28 04:12:30 +00:00
|
|
|
/* Create the context for the dst module */
|
|
|
|
if (mode & SIG_MODE_INIT) {
|
|
|
|
status = dst_context_create(key, dhcp_gbl_ctx.mctx, dctx);
|
|
|
|
if (status != ISC_R_SUCCESS) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we have any data add it to the context */
|
|
|
|
if (len != 0) {
|
|
|
|
isc_region_t region;
|
|
|
|
region.base = (unsigned char *)data;
|
|
|
|
region.length = len;
|
|
|
|
dst_context_adddata(*dctx, ®ion);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finish the signature and clean up the context */
|
2000-08-03 21:00:41 +00:00
|
|
|
if (mode & SIG_MODE_FINAL) {
|
2009-10-28 04:12:30 +00:00
|
|
|
unsigned int sigsize;
|
|
|
|
isc_buffer_t sigbuf;
|
|
|
|
|
|
|
|
status = dst_key_sigsize(key, &sigsize);
|
|
|
|
if (status != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2000-08-03 21:00:41 +00:00
|
|
|
status = omapi_typed_data_new (MDL, &td,
|
|
|
|
omapi_datatype_data,
|
2009-10-28 04:12:30 +00:00
|
|
|
sigsize);
|
|
|
|
if (status != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2000-08-03 21:00:41 +00:00
|
|
|
|
2009-10-28 04:12:30 +00:00
|
|
|
isc_buffer_init(&sigbuf, td->u.buffer.value, td->u.buffer.len);
|
|
|
|
status = dst_context_sign(*dctx, &sigbuf);
|
|
|
|
if (status != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2000-08-03 21:00:41 +00:00
|
|
|
|
2009-10-28 04:12:30 +00:00
|
|
|
if (result) {
|
|
|
|
omapi_typed_data_reference (result, td, MDL);
|
|
|
|
}
|
2000-08-03 21:00:41 +00:00
|
|
|
|
2009-10-28 04:12:30 +00:00
|
|
|
cleanup:
|
|
|
|
/* We are done with the context and the td. On success
|
|
|
|
* the td is now referenced from result, on failure we
|
|
|
|
* don't need it any more */
|
|
|
|
if (td) {
|
2000-08-03 21:00:41 +00:00
|
|
|
omapi_typed_data_dereference (&td, MDL);
|
2009-10-28 04:12:30 +00:00
|
|
|
}
|
|
|
|
dst_context_destroy(dctx);
|
|
|
|
return status;
|
2000-08-03 21:00:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t omapi_connection_output_auth_length (omapi_object_t *h,
|
|
|
|
unsigned *l)
|
|
|
|
{
|
|
|
|
omapi_connection_object_t *c;
|
|
|
|
|
2009-10-28 04:12:30 +00:00
|
|
|
if (h->type != omapi_type_connection)
|
|
|
|
return DHCP_R_INVALIDARG;
|
2000-08-03 21:00:41 +00:00
|
|
|
c = (omapi_connection_object_t *)h;
|
|
|
|
|
2009-10-28 04:12:30 +00:00
|
|
|
if (c->out_key == NULL)
|
2000-08-03 21:00:41 +00:00
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
|
2009-10-28 04:12:30 +00:00
|
|
|
return(dst_key_sigsize(c->out_key, l));
|
2000-08-03 21:00:41 +00:00
|
|
|
}
|
|
|
|
|
1999-09-02 00:32:56 +00:00
|
|
|
isc_result_t omapi_connection_set_value (omapi_object_t *h,
|
|
|
|
omapi_object_t *id,
|
|
|
|
omapi_data_string_t *name,
|
|
|
|
omapi_typed_data_t *value)
|
|
|
|
{
|
2000-08-03 21:00:41 +00:00
|
|
|
omapi_connection_object_t *c;
|
|
|
|
isc_result_t status;
|
|
|
|
|
1999-09-02 00:32:56 +00:00
|
|
|
if (h -> type != omapi_type_connection)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
2000-08-03 21:00:41 +00:00
|
|
|
c = (omapi_connection_object_t *)h;
|
|
|
|
|
|
|
|
if (omapi_ds_strcmp (name, "input-authenticator") == 0) {
|
|
|
|
if (value && value -> type != omapi_datatype_object)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
2000-08-03 21:00:41 +00:00
|
|
|
|
|
|
|
if (c -> in_context) {
|
|
|
|
omapi_connection_sign_data (SIG_MODE_FINAL,
|
|
|
|
c -> in_key,
|
|
|
|
&c -> in_context,
|
|
|
|
0, 0,
|
|
|
|
(omapi_typed_data_t **) 0);
|
|
|
|
}
|
|
|
|
|
2009-10-28 04:12:30 +00:00
|
|
|
if (c->in_key != NULL) {
|
|
|
|
dst_key_free(&c->in_key);
|
2000-08-03 21:00:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (value) {
|
|
|
|
status = make_dst_key (&c -> in_key,
|
|
|
|
value -> u.object);
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
else if (omapi_ds_strcmp (name, "output-authenticator") == 0) {
|
|
|
|
if (value && value -> type != omapi_datatype_object)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
2000-08-03 21:00:41 +00:00
|
|
|
|
|
|
|
if (c -> out_context) {
|
|
|
|
omapi_connection_sign_data (SIG_MODE_FINAL,
|
|
|
|
c -> out_key,
|
|
|
|
&c -> out_context,
|
|
|
|
0, 0,
|
|
|
|
(omapi_typed_data_t **) 0);
|
|
|
|
}
|
|
|
|
|
2009-10-28 04:12:30 +00:00
|
|
|
if (c->out_key != NULL) {
|
|
|
|
dst_key_free(&c->out_key);
|
2000-08-03 21:00:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (value) {
|
|
|
|
status = make_dst_key (&c -> out_key,
|
|
|
|
value -> u.object);
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
2022-01-19 20:14:16 +01:00
|
|
|
|
1999-09-02 00:32:56 +00:00
|
|
|
if (h -> inner && h -> inner -> type -> set_value)
|
|
|
|
return (*(h -> inner -> type -> set_value))
|
|
|
|
(h -> inner, id, name, value);
|
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t omapi_connection_get_value (omapi_object_t *h,
|
|
|
|
omapi_object_t *id,
|
|
|
|
omapi_data_string_t *name,
|
|
|
|
omapi_value_t **value)
|
|
|
|
{
|
2000-08-03 21:00:41 +00:00
|
|
|
omapi_connection_object_t *c;
|
|
|
|
omapi_typed_data_t *td = (omapi_typed_data_t *)0;
|
|
|
|
isc_result_t status;
|
2009-10-28 04:12:30 +00:00
|
|
|
unsigned int sigsize;
|
2000-08-03 21:00:41 +00:00
|
|
|
|
1999-09-02 00:32:56 +00:00
|
|
|
if (h -> type != omapi_type_connection)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
2000-08-03 21:00:41 +00:00
|
|
|
c = (omapi_connection_object_t *)h;
|
|
|
|
|
|
|
|
if (omapi_ds_strcmp (name, "input-signature") == 0) {
|
|
|
|
if (!c -> in_key || !c -> in_context)
|
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
|
|
|
|
status = omapi_connection_sign_data (SIG_MODE_FINAL,
|
|
|
|
c -> in_key,
|
|
|
|
&c -> in_context,
|
|
|
|
0, 0, &td);
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
status = omapi_make_value (value, name, td, MDL);
|
|
|
|
omapi_typed_data_dereference (&td, MDL);
|
|
|
|
return status;
|
|
|
|
|
|
|
|
} else if (omapi_ds_strcmp (name, "input-signature-size") == 0) {
|
2009-10-28 04:12:30 +00:00
|
|
|
if (c->in_key == NULL)
|
2000-08-03 21:00:41 +00:00
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
|
2009-10-28 04:12:30 +00:00
|
|
|
status = dst_key_sigsize(c->in_key, &sigsize);
|
|
|
|
if (status != ISC_R_SUCCESS) {
|
|
|
|
return(status);
|
2022-01-19 20:14:16 +01:00
|
|
|
}
|
2009-10-28 04:12:30 +00:00
|
|
|
|
|
|
|
return omapi_make_int_value(value, name, sigsize, MDL);
|
2000-08-03 21:00:41 +00:00
|
|
|
|
|
|
|
} else if (omapi_ds_strcmp (name, "output-signature") == 0) {
|
|
|
|
if (!c -> out_key || !c -> out_context)
|
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
|
|
|
|
status = omapi_connection_sign_data (SIG_MODE_FINAL,
|
|
|
|
c -> out_key,
|
|
|
|
&c -> out_context,
|
|
|
|
0, 0, &td);
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
status = omapi_make_value (value, name, td, MDL);
|
|
|
|
omapi_typed_data_dereference (&td, MDL);
|
|
|
|
return status;
|
|
|
|
|
|
|
|
} else if (omapi_ds_strcmp (name, "output-signature-size") == 0) {
|
2009-10-28 04:12:30 +00:00
|
|
|
if (c->out_key == NULL)
|
2000-08-03 21:00:41 +00:00
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
|
2009-10-28 04:12:30 +00:00
|
|
|
|
|
|
|
status = dst_key_sigsize(c->out_key, &sigsize);
|
|
|
|
if (status != ISC_R_SUCCESS) {
|
|
|
|
return(status);
|
2022-01-19 20:14:16 +01:00
|
|
|
}
|
2009-10-28 04:12:30 +00:00
|
|
|
|
|
|
|
return omapi_make_int_value(value, name, sigsize, MDL);
|
2000-08-03 21:00:41 +00:00
|
|
|
}
|
2022-01-19 20:14:16 +01:00
|
|
|
|
1999-09-02 00:32:56 +00:00
|
|
|
if (h -> inner && h -> inner -> type -> get_value)
|
|
|
|
return (*(h -> inner -> type -> get_value))
|
|
|
|
(h -> inner, id, name, value);
|
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
}
|
|
|
|
|
2000-01-26 14:56:18 +00:00
|
|
|
isc_result_t omapi_connection_destroy (omapi_object_t *h,
|
|
|
|
const char *file, int line)
|
1999-09-02 00:32:56 +00:00
|
|
|
{
|
|
|
|
omapi_connection_object_t *c;
|
|
|
|
|
2000-08-14 21:58:57 +00:00
|
|
|
#ifdef DEBUG_PROTOCOL
|
|
|
|
log_debug ("omapi_connection_destroy()");
|
|
|
|
#endif
|
|
|
|
|
1999-09-02 00:32:56 +00:00
|
|
|
if (h -> type != omapi_type_connection)
|
|
|
|
return ISC_R_UNEXPECTED;
|
|
|
|
c = (omapi_connection_object_t *)(h);
|
|
|
|
if (c -> state == omapi_connection_connected)
|
|
|
|
omapi_disconnect (h, 1);
|
|
|
|
if (c -> listener)
|
2000-05-16 23:03:49 +00:00
|
|
|
omapi_listener_dereference (&c -> listener, file, line);
|
2000-05-01 23:50:16 +00:00
|
|
|
if (c -> connect_list)
|
|
|
|
omapi_addr_list_dereference (&c -> connect_list, file, line);
|
1999-09-02 00:32:56 +00:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t omapi_connection_signal_handler (omapi_object_t *h,
|
1999-10-07 06:36:35 +00:00
|
|
|
const char *name, va_list ap)
|
1999-09-02 00:32:56 +00:00
|
|
|
{
|
|
|
|
if (h -> type != omapi_type_connection)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
2000-08-14 21:58:57 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG_PROTOCOL
|
|
|
|
log_debug ("omapi_connection_signal_handler(%s)", name);
|
|
|
|
#endif
|
2022-01-19 20:14:16 +01:00
|
|
|
|
1999-09-02 00:32:56 +00:00
|
|
|
if (h -> inner && h -> inner -> type -> signal_handler)
|
|
|
|
return (*(h -> inner -> type -> signal_handler)) (h -> inner,
|
|
|
|
name, ap);
|
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write all the published values associated with the object through the
|
|
|
|
specified connection. */
|
|
|
|
|
|
|
|
isc_result_t omapi_connection_stuff_values (omapi_object_t *c,
|
|
|
|
omapi_object_t *id,
|
|
|
|
omapi_object_t *m)
|
|
|
|
{
|
|
|
|
if (m -> type != omapi_type_connection)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
1999-09-02 00:32:56 +00:00
|
|
|
|
|
|
|
if (m -> inner && m -> inner -> type -> stuff_values)
|
|
|
|
return (*(m -> inner -> type -> stuff_values)) (c, id,
|
|
|
|
m -> inner);
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
2020-12-14 11:28:37 -05:00
|
|
|
|
|
|
|
/* @brief Fetches the value of an attribute in an object as an allocated
|
|
|
|
* C string
|
|
|
|
*
|
|
|
|
* @param obj ompapi object containing the desire attribute
|
|
|
|
* @param attr_name name of the desired attribute
|
|
|
|
* @param[out] cstr pointer in which to place the allocated C string's address
|
|
|
|
*
|
|
|
|
* Caller is responsible for freeing (via dfree) the allocated string.
|
|
|
|
*
|
|
|
|
* @return ISC_R_SUCCESS if successful, otherwise indicates the type of failure
|
|
|
|
*/
|
|
|
|
static isc_result_t ctring_from_attribute(omapi_object_t *obj, char *attr_name,
|
|
|
|
char **cstr) {
|
|
|
|
isc_result_t status = ISC_R_SUCCESS;
|
|
|
|
omapi_value_t *attr = 0;
|
|
|
|
|
|
|
|
/* Find the attribute in the object. */
|
|
|
|
status = omapi_get_value_str(obj, (omapi_object_t *)0, attr_name,
|
|
|
|
&attr);
|
|
|
|
if (status != ISC_R_SUCCESS) {
|
|
|
|
return (status);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Got it, let's make sure it's either data or string type. */
|
|
|
|
if (attr->value->type != omapi_datatype_data &&
|
|
|
|
attr->value->type != omapi_datatype_string) {
|
|
|
|
return (DHCP_R_INVALIDARG);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make a C string from the attribute value. */
|
|
|
|
*cstr = dmalloc (attr->value->u.buffer.len + 1, MDL);
|
|
|
|
if (!(*cstr)) {
|
|
|
|
status = ISC_R_NOMEMORY;
|
|
|
|
} else {
|
|
|
|
memcpy (*cstr, attr->value->u.buffer.value,
|
|
|
|
attr->value->u.buffer.len);
|
|
|
|
(*cstr)[attr->value->u.buffer.len] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get rid of the attribute reference */
|
|
|
|
if (attr) {
|
|
|
|
omapi_value_dereference (&attr, MDL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (status);
|
|
|
|
}
|