ISC DHCP  4.4.3-P1
A reference DHCPv4 and DHCPv6 implementation
connection.c
Go to the documentation of this file.
1 /* connection.c
2 
3  Subroutines for dealing with connections. */
4 
5 /*
6  * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1999-2003 by Internet Software Consortium
8  *
9  * This Source Code Form is subject to the terms of the Mozilla Public
10  * License, v. 2.0. If a copy of the MPL was not distributed with this
11  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *
21  * Internet Systems Consortium, Inc.
22  * PO Box 360
23  * Newmarket, NH 03857 USA
24  * <info@isc.org>
25  * https://www.isc.org/
26  *
27  */
28 
29 #include "dhcpd.h"
30 #include <isc/util.h>
31 #include <omapip/omapip_p.h>
32 #include <arpa/inet.h>
33 #include <arpa/nameser.h>
34 #include <errno.h>
35 
36 #if defined (TRACING)
37 static void trace_connect_input (trace_type_t *, unsigned, char *);
38 static void trace_connect_stop (trace_type_t *);
39 static void trace_disconnect_input (trace_type_t *, unsigned, char *);
40 static void trace_disconnect_stop (trace_type_t *);
41 trace_type_t *trace_connect;
42 trace_type_t *trace_disconnect;
43 extern omapi_array_t *trace_listeners;
44 #endif
45 static isc_result_t omapi_connection_connect_internal (omapi_object_t *);
46 
47 static isc_result_t ctring_from_attribute(omapi_object_t *obj, char *attr_name,
48  char **cstr);
49 
50 OMAPI_OBJECT_ALLOC (omapi_connection,
52 
53 isc_result_t omapi_connect (omapi_object_t *c,
54  const char *server_name,
55  unsigned port)
56 {
57  struct hostent *he;
58  unsigned i, hix;
60  struct in_addr foo;
61  isc_result_t status;
62 
63 #ifdef DEBUG_PROTOCOL
64  log_debug ("omapi_connect(%s, port=%d)", server_name, port);
65 #endif
66 
67  if (!inet_aton (server_name, &foo)) {
68  /* If we didn't get a numeric address, try for a domain
69  name. It's okay for this call to block. */
70  he = gethostbyname (server_name);
71  if (!he)
72  return DHCP_R_HOSTUNKNOWN;
73  for (i = 0; he -> h_addr_list [i]; i++)
74  ;
75  if (i == 0)
76  return DHCP_R_HOSTUNKNOWN;
77  hix = i;
78 
79  status = omapi_addr_list_new (&addrs, hix, MDL);
80  if (status != ISC_R_SUCCESS)
81  return status;
82  for (i = 0; i < hix; i++) {
83  addrs -> addresses [i].addrtype = he -> h_addrtype;
84  addrs -> addresses [i].addrlen = he -> h_length;
85  memcpy (addrs -> addresses [i].address,
86  he -> h_addr_list [i],
87  (unsigned)he -> h_length);
88  addrs -> addresses [i].port = port;
89  }
90  } else {
91  status = omapi_addr_list_new (&addrs, 1, MDL);
92  if (status != ISC_R_SUCCESS)
93  return status;
94  addrs -> addresses [0].addrtype = AF_INET;
95  addrs -> addresses [0].addrlen = sizeof foo;
96  memcpy (addrs -> addresses [0].address, &foo, sizeof foo);
97  addrs -> addresses [0].port = port;
98  }
99  status = omapi_connect_list (c, addrs, (omapi_addr_t *)0);
101  return status;
102 }
103 
105  omapi_addr_list_t *remote_addrs,
106  omapi_addr_t *local_addr)
107 {
108  isc_result_t status;
110  int flag;
111  struct sockaddr_in local_sin;
112 
113  obj = (omapi_connection_object_t *)0;
114  status = omapi_connection_allocate (&obj, MDL);
115  if (status != ISC_R_SUCCESS)
116  return status;
117 
118  status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj,
119  MDL);
120  if (status != ISC_R_SUCCESS) {
121  omapi_connection_dereference (&obj, MDL);
122  return status;
123  }
124  status = omapi_object_reference (&obj -> inner, c, MDL);
125  if (status != ISC_R_SUCCESS) {
126  omapi_connection_dereference (&obj, MDL);
127  return status;
128  }
129 
130  /* Store the address list on the object. */
131  omapi_addr_list_reference (&obj -> connect_list, remote_addrs, MDL);
132  obj -> cptr = 0;
133  obj -> state = omapi_connection_unconnected;
134 
135 #if defined (TRACING)
136  /* If we're playing back, don't actually try to connect - just leave
137  the object available for a subsequent connect or disconnect. */
138  if (!trace_playback ()) {
139 #endif
140  /* Create a socket on which to communicate. */
141  obj -> socket =
142  socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
143  if (obj -> socket < 0) {
144  omapi_connection_dereference (&obj, MDL);
145  if (errno == EMFILE || errno == ENFILE
146  || errno == ENOBUFS)
147  return ISC_R_NORESOURCES;
148  return ISC_R_UNEXPECTED;
149  }
150 
151  /* Set up the local address, if any. */
152  if (local_addr) {
153  /* Only do TCPv4 so far. */
154  if (local_addr -> addrtype != AF_INET) {
155  close(obj->socket);
156  omapi_connection_dereference (&obj, MDL);
157  return DHCP_R_INVALIDARG;
158  }
159  local_sin.sin_port = htons (local_addr -> port);
160  memcpy (&local_sin.sin_addr,
161  local_addr -> address,
162  local_addr -> addrlen);
163 #if defined (HAVE_SA_LEN)
164  local_sin.sin_len = sizeof local_addr;
165 #endif
166  local_sin.sin_family = AF_INET;
167  memset (&local_sin.sin_zero, 0,
168  sizeof local_sin.sin_zero);
169 
170  if (bind (obj -> socket, (struct sockaddr *)&local_sin,
171  sizeof local_sin) < 0) {
172  omapi_connection_object_t **objp = &obj;
173  omapi_object_t **o = (omapi_object_t **)objp;
174  close(obj->socket);
176  if (errno == EADDRINUSE)
177  return ISC_R_ADDRINUSE;
178  if (errno == EADDRNOTAVAIL)
179  return ISC_R_ADDRNOTAVAIL;
180  if (errno == EACCES)
181  return ISC_R_NOPERM;
182  return ISC_R_UNEXPECTED;
183  }
184  obj -> local_addr = local_sin;
185  }
186 
187 #if defined(F_SETFD)
188  if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
189  close (obj -> socket);
190  omapi_connection_dereference (&obj, MDL);
191  return ISC_R_UNEXPECTED;
192  }
193 #endif
194 
195  /* Set the SO_REUSEADDR flag (this should not fail). */
196  flag = 1;
197  if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
198  (char *)&flag, sizeof flag) < 0) {
199  omapi_connection_dereference (&obj, MDL);
200  return ISC_R_UNEXPECTED;
201  }
202 
203  /* Set the file to nonblocking mode. */
204  if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
205  omapi_connection_dereference (&obj, MDL);
206  return ISC_R_UNEXPECTED;
207  }
208 
209 #ifdef SO_NOSIGPIPE
210  /*
211  * If available stop the OS from killing our
212  * program on a SIGPIPE failure
213  */
214  flag = 1;
215  if (setsockopt(obj->socket, SOL_SOCKET, SO_NOSIGPIPE,
216  (char *)&flag, sizeof(flag)) < 0) {
217  omapi_connection_dereference (&obj, MDL);
218  return ISC_R_UNEXPECTED;
219  }
220 #endif
221 
222  status = (omapi_register_io_object
223  ((omapi_object_t *)obj,
227  if (status != ISC_R_SUCCESS)
228  goto out;
229  status = omapi_connection_connect_internal ((omapi_object_t *)
230  obj);
231  /*
232  * inprogress is the same as success but used
233  * to indicate to the dispatch code that we should
234  * mark the socket as requiring more attention.
235  * Routines calling this function should handle
236  * success properly.
237  */
238  if (status == ISC_R_INPROGRESS) {
239  status = ISC_R_SUCCESS;
240  }
241 #if defined (TRACING)
242  }
244 #endif
245 
246  out:
247  omapi_connection_dereference (&obj, MDL);
248  return status;
249 }
250 
251 #if defined (TRACING)
252 omapi_array_t *omapi_connections;
253 
255 
256 void omapi_connection_trace_setup (void) {
257  trace_connect = trace_type_register ("connect", (void *)0,
258  trace_connect_input,
259  trace_connect_stop, MDL);
260  trace_disconnect = trace_type_register ("disconnect", (void *)0,
261  trace_disconnect_input,
262  trace_disconnect_stop, MDL);
263 }
264 
266  const char *file, int line)
267 {
268  isc_result_t status;
269  trace_iov_t iov [6];
270  int iov_count = 0;
271  int32_t connect_index, listener_index;
272  static int32_t index;
273 
274  if (!omapi_connections) {
275  status = omapi_connection_array_allocate (&omapi_connections,
276  file, line);
277  if (status != ISC_R_SUCCESS)
278  return;
279  }
280 
281  status = omapi_connection_array_extend (omapi_connections, obj,
282  (int *)0, file, line);
283  if (status != ISC_R_SUCCESS) {
284  obj -> index = -1;
285  return;
286  }
287 
288 #if defined (TRACING)
289  if (trace_record ()) {
290  /* Connection registration packet:
291 
292  int32_t index
293  int32_t listener_index [-1 means no listener]
294  u_int16_t remote_port
295  u_int16_t local_port
296  u_int32_t remote_addr
297  u_int32_t local_addr */
298 
299  connect_index = htonl (index);
300  index++;
301  if (obj -> listener)
302  listener_index = htonl (obj -> listener -> index);
303  else
304  listener_index = htonl (-1);
305  iov [iov_count].buf = (char *)&connect_index;
306  iov [iov_count++].len = sizeof connect_index;
307  iov [iov_count].buf = (char *)&listener_index;
308  iov [iov_count++].len = sizeof listener_index;
309  iov [iov_count].buf = (char *)&obj -> remote_addr.sin_port;
310  iov [iov_count++].len = sizeof obj -> remote_addr.sin_port;
311  iov [iov_count].buf = (char *)&obj -> local_addr.sin_port;
312  iov [iov_count++].len = sizeof obj -> local_addr.sin_port;
313  iov [iov_count].buf = (char *)&obj -> remote_addr.sin_addr;
314  iov [iov_count++].len = sizeof obj -> remote_addr.sin_addr;
315  iov [iov_count].buf = (char *)&obj -> local_addr.sin_addr;
316  iov [iov_count++].len = sizeof obj -> local_addr.sin_addr;
317 
318  status = trace_write_packet_iov (trace_connect,
319  iov_count, iov, file, line);
320  }
321 #endif
322 }
323 
324 static void trace_connect_input (trace_type_t *ttype,
325  unsigned length, char *buf)
326 {
327  struct sockaddr_in remote, local;
328  int32_t connect_index, listener_index;
329  char *s = buf;
331  isc_result_t status;
332  int i;
333 
334  if (length != ((sizeof connect_index) +
335  (sizeof remote.sin_port) +
336  (sizeof remote.sin_addr)) * 2) {
337  log_error ("Trace connect: invalid length %d", length);
338  return;
339  }
340 
341  memset (&remote, 0, sizeof remote);
342  memset (&local, 0, sizeof local);
343  memcpy (&connect_index, s, sizeof connect_index);
344  s += sizeof connect_index;
345  memcpy (&listener_index, s, sizeof listener_index);
346  s += sizeof listener_index;
347  memcpy (&remote.sin_port, s, sizeof remote.sin_port);
348  s += sizeof remote.sin_port;
349  memcpy (&local.sin_port, s, sizeof local.sin_port);
350  s += sizeof local.sin_port;
351  memcpy (&remote.sin_addr, s, sizeof remote.sin_addr);
352  s += sizeof remote.sin_addr;
353  memcpy (&local.sin_addr, s, sizeof local.sin_addr);
354  s += sizeof local.sin_addr;
355  POST(s);
356 
357  connect_index = ntohl (connect_index);
358  listener_index = ntohl (listener_index);
359 
360  /* If this was a connect to a listener, then we just slap together
361  a new connection. */
362  if (listener_index != -1) {
363  omapi_listener_object_t *listener;
364  listener = (omapi_listener_object_t *)0;
365  omapi_array_foreach_begin (trace_listeners,
367  if (lp -> address.sin_port == local.sin_port) {
368  omapi_listener_reference (&listener, lp, MDL);
369  omapi_listener_dereference (&lp, MDL);
370  break;
371  }
372  } omapi_array_foreach_end (trace_listeners,
374  if (!listener) {
375  log_error ("%s%ld, addr %s, port %d",
376  "Spurious traced listener connect - index ",
377  (long int)listener_index,
378  inet_ntoa (local.sin_addr),
379  ntohs (local.sin_port));
380  return;
381  }
382  obj = (omapi_connection_object_t *)0;
383  status = omapi_listener_connect (&obj, listener, -1, &remote);
384  if (status != ISC_R_SUCCESS) {
385  log_error ("traced listener connect: %s",
386  isc_result_totext (status));
387  }
388  if (obj)
389  omapi_connection_dereference (&obj, MDL);
390  omapi_listener_dereference (&listener, MDL);
391  return;
392  }
393 
394  /* Find the matching connect object, if there is one. */
395  omapi_array_foreach_begin (omapi_connections,
397  for (i = 0; (lp->connect_list &&
398  i < lp->connect_list->count); i++) {
399  if (!memcmp (&remote.sin_addr,
400  &lp->connect_list->addresses[i].address,
401  sizeof remote.sin_addr) &&
402  (ntohs (remote.sin_port) ==
403  lp->connect_list->addresses[i].port)) {
404  lp->state = omapi_connection_connected;
405  lp->remote_addr = remote;
406  lp->remote_addr.sin_family = AF_INET;
407  omapi_addr_list_dereference(&lp->connect_list, MDL);
408  lp->index = connect_index;
409  status = omapi_signal_in((omapi_object_t *)lp,
410  "connect");
411  omapi_connection_dereference (&lp, MDL);
412  return;
413  }
414  }
415  } omapi_array_foreach_end (omapi_connections,
417 
418  log_error ("Spurious traced connect - index %ld, addr %s, port %d",
419  (long int)connect_index, inet_ntoa (remote.sin_addr),
420  ntohs (remote.sin_port));
421  return;
422 }
423 
424 static void trace_connect_stop (trace_type_t *ttype) { }
425 
426 static void trace_disconnect_input (trace_type_t *ttype,
427  unsigned length, char *buf)
428 {
429  int32_t *index;
430  if (length != sizeof *index) {
431  log_error ("trace disconnect: wrong length %d", length);
432  return;
433  }
434 
435  index = (int32_t *)buf;
436 
437  omapi_array_foreach_begin (omapi_connections,
439  if (lp -> index == ntohl (*index)) {
440  omapi_disconnect ((omapi_object_t *)lp, 1);
441  omapi_connection_dereference (&lp, MDL);
442  return;
443  }
444  } omapi_array_foreach_end (omapi_connections,
446 
447  log_error ("trace disconnect: no connection matching index %ld",
448  (long int)ntohl (*index));
449 }
450 
451 static void trace_disconnect_stop (trace_type_t *ttype) { }
452 #endif
453 
454 /* Disconnect a connection object from the remote end. If force is nonzero,
455  close the connection immediately. Otherwise, shut down the receiving end
456  but allow any unsent data to be sent before actually closing the socket. */
457 
459  int force)
460 {
462 
463 #ifdef DEBUG_PROTOCOL
464  log_debug ("omapi_disconnect(force=%d)", force);
465 #endif
466 
467  c = (omapi_connection_object_t *)h;
468  if (c -> type != omapi_type_connection)
469  return DHCP_R_INVALIDARG;
470 
471 #if defined (TRACING)
472  if (trace_record ()) {
473  isc_result_t status;
474  int32_t index;
475 
476  index = htonl (c -> index);
477  status = trace_write_packet (trace_disconnect,
478  sizeof index, (char *)&index,
479  MDL);
480  if (status != ISC_R_SUCCESS) {
481  trace_stop ();
482  log_error ("trace_write_packet: %s",
483  isc_result_totext (status));
484  }
485  }
486  if (!trace_playback ()) {
487 #endif
488  if (!force) {
489  /* If we're already disconnecting, we don't have to do
490  anything. */
491  if (c -> state == omapi_connection_disconnecting)
492  return ISC_R_SUCCESS;
493 
494  /* Try to shut down the socket - this sends a FIN to
495  the remote end, so that it won't send us any more
496  data. If the shutdown succeeds, and we still
497  have bytes left to write, defer closing the socket
498  until that's done. */
499  if (!shutdown (c -> socket, SHUT_RD)) {
500  if (c -> out_bytes > 0) {
501  c -> state =
503  return ISC_R_SUCCESS;
504  }
505  }
506  }
507  close (c -> socket);
508 #if defined (TRACING)
509  }
510 #endif
511  c -> state = omapi_connection_closed;
512 
513 #if 0
514  /*
515  * Disconnecting from the I/O object seems incorrect as it doesn't
516  * cause the I/O object to be cleaned and released. Previous to
517  * using the isc socket library this wouldn't have caused a problem
518  * with the socket library we would have a reference to a closed
519  * socket. Instead we now do an unregister to properly free the
520  * I/O object.
521  */
522 
523  /* Disconnect from I/O object, if any. */
524  if (h -> outer) {
525  if (h -> outer -> inner)
526  omapi_object_dereference (&h -> outer -> inner, MDL);
527  omapi_object_dereference (&h -> outer, MDL);
528  }
529 #else
530  if (h->outer) {
532  }
533 #endif
534 
535  /* If whatever created us registered a signal handler, send it
536  a disconnect signal. */
537  omapi_signal (h, "disconnect", h);
538 
539  /* Disconnect from protocol object, if any. */
540  if (h->inner != NULL) {
541  if (h->inner->outer != NULL) {
542  omapi_object_dereference(&h->inner->outer, MDL);
543  }
544  omapi_object_dereference(&h->inner, MDL);
545  }
546 
547  /* XXX: the code to free buffers should be in the dereference
548  function, but there is no special-purpose function to
549  dereference connections, so these just get leaked */
550  /* Free any buffers */
551  if (c->inbufs != NULL) {
553  }
554  c->in_bytes = 0;
555  if (c->outbufs != NULL) {
557  }
558  c->out_bytes = 0;
559 
560  return ISC_R_SUCCESS;
561 }
562 
563 isc_result_t omapi_connection_require (omapi_object_t *h, unsigned bytes)
564 {
566 
567  if (h -> type != omapi_type_connection)
568  return DHCP_R_INVALIDARG;
569  c = (omapi_connection_object_t *)h;
570 
571  c -> bytes_needed = bytes;
572  if (c -> bytes_needed <= c -> in_bytes) {
573  return ISC_R_SUCCESS;
574  }
575  return DHCP_R_NOTYET;
576 }
577 
578 /* Return the socket on which the dispatcher should wait for readiness
579  to read, for a connection object. */
581 {
583  if (h -> type != omapi_type_connection)
584  return -1;
585  c = (omapi_connection_object_t *)h;
586  if (c -> state != omapi_connection_connected)
587  return -1;
588  return c -> socket;
589 }
590 
591 /*
592  * Return the socket on which the dispatcher should wait for readiness
593  * to write, for a connection object. When bytes are buffered we should
594  * also poke the dispatcher to tell it to start or re-start watching the
595  * socket.
596  */
598 {
600  if (h -> type != omapi_type_connection)
601  return -1;
602  c = (omapi_connection_object_t *)h;
603  return c->socket;
604 }
605 
607 {
608  isc_result_t status;
609 
610  /*
611  * We use the INPROGRESS status to indicate that
612  * we want more from the socket. In this case we
613  * have now connected and are trying to write to
614  * the socket for the first time. For the signaling
615  * code this is the same as a SUCCESS so we don't
616  * pass it on as a signal.
617  */
618  status = omapi_connection_connect_internal (h);
619  if (status == ISC_R_INPROGRESS)
620  return ISC_R_INPROGRESS;
621 
622  if (status != ISC_R_SUCCESS)
623  omapi_signal (h, "status", status);
624 
625  return ISC_R_SUCCESS;
626 }
627 
628 static isc_result_t omapi_connection_connect_internal (omapi_object_t *h)
629 {
630  int error = 0;
632  socklen_t sl;
633  isc_result_t status;
634 
635  if (h -> type != omapi_type_connection)
636  return DHCP_R_INVALIDARG;
637  c = (omapi_connection_object_t *)h;
638 
639  if (c -> state == omapi_connection_connecting) {
640  sl = sizeof error;
641  if (getsockopt (c -> socket, SOL_SOCKET, SO_ERROR,
642  (char *)&error, &sl) < 0) {
643  omapi_disconnect (h, 1);
644  return ISC_R_SUCCESS;
645  }
646  if (!error)
647  c -> state = omapi_connection_connected;
648  }
649  if (c -> state == omapi_connection_connecting ||
650  c -> state == omapi_connection_unconnected) {
651  if (c -> cptr >= c -> connect_list -> count) {
652  switch (error) {
653  case ECONNREFUSED:
654  status = ISC_R_CONNREFUSED;
655  break;
656  case ENETUNREACH:
657  status = ISC_R_NETUNREACH;
658  break;
659  default:
660  status = uerr2isc (error);
661  break;
662  }
663  omapi_disconnect (h, 1);
664  return status;
665  }
666 
667  if (c -> connect_list -> addresses [c -> cptr].addrtype !=
668  AF_INET) {
669  omapi_disconnect (h, 1);
670  return DHCP_R_INVALIDARG;
671  }
672 
673  memcpy (&c -> remote_addr.sin_addr,
674  &c -> connect_list -> addresses [c -> cptr].address,
675  sizeof c -> remote_addr.sin_addr);
676  c -> remote_addr.sin_family = AF_INET;
677  c -> remote_addr.sin_port =
678  htons (c -> connect_list -> addresses [c -> cptr].port);
679 #if defined (HAVE_SA_LEN)
680  c -> remote_addr.sin_len = sizeof c -> remote_addr;
681 #endif
682  memset (&c -> remote_addr.sin_zero, 0,
683  sizeof c -> remote_addr.sin_zero);
684  ++c -> cptr;
685 
686  error = connect (c -> socket,
687  (struct sockaddr *)&c -> remote_addr,
688  sizeof c -> remote_addr);
689  if (error < 0) {
690  error = errno;
691  if (error != EINPROGRESS) {
692  omapi_disconnect (h, 1);
693  switch (error) {
694  case ECONNREFUSED:
695  status = ISC_R_CONNREFUSED;
696  break;
697  case ENETUNREACH:
698  status = ISC_R_NETUNREACH;
699  break;
700  default:
701  status = uerr2isc (error);
702  break;
703  }
704  return status;
705  }
706  c -> state = omapi_connection_connecting;
707  return DHCP_R_INCOMPLETE;
708  }
709  c -> state = omapi_connection_connected;
710  }
711 
712  /* I don't know why this would fail, so I'm tempted not to test
713  the return value. */
714  sl = sizeof (c -> local_addr);
715  if (getsockname (c -> socket,
716  (struct sockaddr *)&c -> local_addr, &sl) < 0) {
717  }
718 
719  /* Reregister with the I/O object. If we don't already have an
720  I/O object this turns into a register call, otherwise we simply
721  modify the pointers in the I/O object. */
722 
723  status = omapi_reregister_io_object (h,
729 
730  if (status != ISC_R_SUCCESS) {
731  omapi_disconnect (h, 1);
732  return status;
733  }
734 
735  omapi_signal_in (h, "connect");
736  omapi_addr_list_dereference (&c -> connect_list, MDL);
737  return ISC_R_INPROGRESS;
738 }
739 
740 /* Reaper function for connection - if the connection is completely closed,
741  reap it. If it's in the disconnecting state, there were bytes left
742  to write when the user closed it, so if there are now no bytes left to
743  write, we can close it. */
745 {
747 
748  if (h -> type != omapi_type_connection)
749  return DHCP_R_INVALIDARG;
750 
751  c = (omapi_connection_object_t *)h;
752  if (c -> state == omapi_connection_disconnecting &&
753  c -> out_bytes == 0) {
754 #ifdef DEBUG_PROTOCOL
755  log_debug ("omapi_connection_reaper(): disconnect");
756 #endif
757  omapi_disconnect (h, 1);
758  }
759  if (c -> state == omapi_connection_closed) {
760 #ifdef DEBUG_PROTOCOL
761  log_debug ("omapi_connection_reaper(): closed");
762 #endif
763  return ISC_R_NOTCONNECTED;
764  }
765  return ISC_R_SUCCESS;
766 }
767 
768 static isc_result_t make_dst_key (dst_key_t **dst_key, omapi_object_t *a) {
769  omapi_value_t *key = 0;
770  char *name_str = 0;
771  char *algorithm_str = 0;
772  isc_result_t status = ISC_R_SUCCESS;
773 
774  /* Get the key name as a C string. */
775  status = ctring_from_attribute(a, "name", &name_str);
776  if (status == ISC_R_SUCCESS) {
777  /* Get the algorithm name as a C string. */
778  status = ctring_from_attribute(a, "algorithm", &algorithm_str);
779  if (status == ISC_R_SUCCESS) {
780  /* Get the key secret value */
781  status = omapi_get_value_str(a, 0, "key", &key);
782  if (status == ISC_R_SUCCESS) {
783  /* Now let's try and create the key */
784  status = isclib_make_dst_key(
785  name_str,
786  algorithm_str,
787  key->value->u.buffer.value,
788  key->value->u.buffer.len,
789  dst_key);
790 
791  if (*dst_key == NULL) {
792  status = ISC_R_NOMEMORY;
793  }
794  }
795  }
796  }
797 
798  if (name_str)
799  dfree (name_str, MDL);
800  if (algorithm_str)
801  dfree (algorithm_str, MDL);
802  if (key)
804 
805  return status;
806 }
807 
808 isc_result_t omapi_connection_sign_data (int mode,
809  dst_key_t *key,
810  void **context,
811  const unsigned char *data,
812  const unsigned len,
813  omapi_typed_data_t **result)
814 {
816  isc_result_t status;
817  dst_context_t **dctx = (dst_context_t **)context;
818 
819  /* Create the context for the dst module */
820  if (mode & SIG_MODE_INIT) {
821  status = dst_context_create(key, dhcp_gbl_ctx.mctx, dctx);
822  if (status != ISC_R_SUCCESS) {
823  return status;
824  }
825  }
826 
827  /* If we have any data add it to the context */
828  if (len != 0) {
829  isc_region_t region;
830  region.base = (unsigned char *)data;
831  region.length = len;
832  dst_context_adddata(*dctx, &region);
833  }
834 
835  /* Finish the signature and clean up the context */
836  if (mode & SIG_MODE_FINAL) {
837  unsigned int sigsize;
838  isc_buffer_t sigbuf;
839 
840  status = dst_key_sigsize(key, &sigsize);
841  if (status != ISC_R_SUCCESS) {
842  goto cleanup;
843  }
844 
845  status = omapi_typed_data_new (MDL, &td,
847  sigsize);
848  if (status != ISC_R_SUCCESS) {
849  goto cleanup;
850  }
851 
852  isc_buffer_init(&sigbuf, td->u.buffer.value, td->u.buffer.len);
853  status = dst_context_sign(*dctx, &sigbuf);
854  if (status != ISC_R_SUCCESS) {
855  goto cleanup;
856  }
857 
858  if (result) {
859  omapi_typed_data_reference (result, td, MDL);
860  }
861 
862  cleanup:
863  /* We are done with the context and the td. On success
864  * the td is now referenced from result, on failure we
865  * don't need it any more */
866  if (td) {
868  }
869  dst_context_destroy(dctx);
870  return status;
871  }
872 
873  return ISC_R_SUCCESS;
874 }
875 
877  unsigned *l)
878 {
880 
881  if (h->type != omapi_type_connection)
882  return DHCP_R_INVALIDARG;
883  c = (omapi_connection_object_t *)h;
884 
885  if (c->out_key == NULL)
886  return ISC_R_NOTFOUND;
887 
888  return(dst_key_sigsize(c->out_key, l));
889 }
890 
892  omapi_object_t *id,
893  omapi_data_string_t *name,
895 {
897  isc_result_t status;
898 
899  if (h -> type != omapi_type_connection)
900  return DHCP_R_INVALIDARG;
901  c = (omapi_connection_object_t *)h;
902 
903  if (omapi_ds_strcmp (name, "input-authenticator") == 0) {
904  if (value && value -> type != omapi_datatype_object)
905  return DHCP_R_INVALIDARG;
906 
907  if (c -> in_context) {
909  c -> in_key,
910  &c -> in_context,
911  0, 0,
912  (omapi_typed_data_t **) 0);
913  }
914 
915  if (c->in_key != NULL) {
916  dst_key_free(&c->in_key);
917  }
918 
919  if (value) {
920  status = make_dst_key (&c -> in_key,
921  value -> u.object);
922  if (status != ISC_R_SUCCESS)
923  return status;
924  }
925 
926  return ISC_R_SUCCESS;
927  }
928  else if (omapi_ds_strcmp (name, "output-authenticator") == 0) {
929  if (value && value -> type != omapi_datatype_object)
930  return DHCP_R_INVALIDARG;
931 
932  if (c -> out_context) {
934  c -> out_key,
935  &c -> out_context,
936  0, 0,
937  (omapi_typed_data_t **) 0);
938  }
939 
940  if (c->out_key != NULL) {
941  dst_key_free(&c->out_key);
942  }
943 
944  if (value) {
945  status = make_dst_key (&c -> out_key,
946  value -> u.object);
947  if (status != ISC_R_SUCCESS)
948  return status;
949  }
950 
951  return ISC_R_SUCCESS;
952  }
953 
954  if (h -> inner && h -> inner -> type -> set_value)
955  return (*(h -> inner -> type -> set_value))
956  (h -> inner, id, name, value);
957  return ISC_R_NOTFOUND;
958 }
959 
961  omapi_object_t *id,
962  omapi_data_string_t *name,
964 {
967  isc_result_t status;
968  unsigned int sigsize;
969 
970  if (h -> type != omapi_type_connection)
971  return DHCP_R_INVALIDARG;
972  c = (omapi_connection_object_t *)h;
973 
974  if (omapi_ds_strcmp (name, "input-signature") == 0) {
975  if (!c -> in_key || !c -> in_context)
976  return ISC_R_NOTFOUND;
977 
979  c -> in_key,
980  &c -> in_context,
981  0, 0, &td);
982  if (status != ISC_R_SUCCESS)
983  return status;
984 
985  status = omapi_make_value (value, name, td, MDL);
987  return status;
988 
989  } else if (omapi_ds_strcmp (name, "input-signature-size") == 0) {
990  if (c->in_key == NULL)
991  return ISC_R_NOTFOUND;
992 
993  status = dst_key_sigsize(c->in_key, &sigsize);
994  if (status != ISC_R_SUCCESS) {
995  return(status);
996  }
997 
998  return omapi_make_int_value(value, name, sigsize, MDL);
999 
1000  } else if (omapi_ds_strcmp (name, "output-signature") == 0) {
1001  if (!c -> out_key || !c -> out_context)
1002  return ISC_R_NOTFOUND;
1003 
1005  c -> out_key,
1006  &c -> out_context,
1007  0, 0, &td);
1008  if (status != ISC_R_SUCCESS)
1009  return status;
1010 
1011  status = omapi_make_value (value, name, td, MDL);
1013  return status;
1014 
1015  } else if (omapi_ds_strcmp (name, "output-signature-size") == 0) {
1016  if (c->out_key == NULL)
1017  return ISC_R_NOTFOUND;
1018 
1019 
1020  status = dst_key_sigsize(c->out_key, &sigsize);
1021  if (status != ISC_R_SUCCESS) {
1022  return(status);
1023  }
1024 
1025  return omapi_make_int_value(value, name, sigsize, MDL);
1026  }
1027 
1028  if (h -> inner && h -> inner -> type -> get_value)
1029  return (*(h -> inner -> type -> get_value))
1030  (h -> inner, id, name, value);
1031  return ISC_R_NOTFOUND;
1032 }
1033 
1035  const char *file, int line)
1036 {
1038 
1039 #ifdef DEBUG_PROTOCOL
1040  log_debug ("omapi_connection_destroy()");
1041 #endif
1042 
1043  if (h -> type != omapi_type_connection)
1044  return ISC_R_UNEXPECTED;
1045  c = (omapi_connection_object_t *)(h);
1046  if (c -> state == omapi_connection_connected)
1047  omapi_disconnect (h, 1);
1048  if (c -> listener)
1049  omapi_listener_dereference (&c -> listener, file, line);
1050  if (c -> connect_list)
1051  omapi_addr_list_dereference (&c -> connect_list, file, line);
1052  return ISC_R_SUCCESS;
1053 }
1054 
1056  const char *name, va_list ap)
1057 {
1058  if (h -> type != omapi_type_connection)
1059  return DHCP_R_INVALIDARG;
1060 
1061 #ifdef DEBUG_PROTOCOL
1062  log_debug ("omapi_connection_signal_handler(%s)", name);
1063 #endif
1064 
1065  if (h -> inner && h -> inner -> type -> signal_handler)
1066  return (*(h -> inner -> type -> signal_handler)) (h -> inner,
1067  name, ap);
1068  return ISC_R_NOTFOUND;
1069 }
1070 
1071 /* Write all the published values associated with the object through the
1072  specified connection. */
1073 
1075  omapi_object_t *id,
1076  omapi_object_t *m)
1077 {
1078  if (m -> type != omapi_type_connection)
1079  return DHCP_R_INVALIDARG;
1080 
1081  if (m -> inner && m -> inner -> type -> stuff_values)
1082  return (*(m -> inner -> type -> stuff_values)) (c, id,
1083  m -> inner);
1084  return ISC_R_SUCCESS;
1085 }
1086 
1087 /* @brief Fetches the value of an attribute in an object as an allocated
1088  * C string
1089  *
1090  * @param obj ompapi object containing the desire attribute
1091  * @param attr_name name of the desired attribute
1092  * @param[out] cstr pointer in which to place the allocated C string's address
1093  *
1094  * Caller is responsible for freeing (via dfree) the allocated string.
1095  *
1096  * @return ISC_R_SUCCESS if successful, otherwise indicates the type of failure
1097 */
1098 static isc_result_t ctring_from_attribute(omapi_object_t *obj, char *attr_name,
1099  char **cstr) {
1100  isc_result_t status = ISC_R_SUCCESS;
1101  omapi_value_t *attr = 0;
1102 
1103  /* Find the attribute in the object. */
1104  status = omapi_get_value_str(obj, (omapi_object_t *)0, attr_name,
1105  &attr);
1106  if (status != ISC_R_SUCCESS) {
1107  return (status);
1108  }
1109 
1110  /* Got it, let's make sure it's either data or string type. */
1111  if (attr->value->type != omapi_datatype_data &&
1112  attr->value->type != omapi_datatype_string) {
1113  return (DHCP_R_INVALIDARG);
1114  }
1115 
1116  /* Make a C string from the attribute value. */
1117  *cstr = dmalloc (attr->value->u.buffer.len + 1, MDL);
1118  if (!(*cstr)) {
1119  status = ISC_R_NOMEMORY;
1120  } else {
1121  memcpy (*cstr, attr->value->u.buffer.value,
1122  attr->value->u.buffer.len);
1123  (*cstr)[attr->value->u.buffer.len] = 0;
1124  }
1125 
1126  /* Get rid of the attribute reference */
1127  if (attr) {
1128  omapi_value_dereference (&attr, MDL);
1129  }
1130 
1131  return (status);
1132 }
const char * buf
Definition: trace.h:75
isc_result_t omapi_reregister_io_object(omapi_object_t *, int(*)(omapi_object_t *), int(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *))
Definition: dispatch.c:305
isc_result_t omapi_disconnect(omapi_object_t *h, int force)
Definition: connection.c:458
isc_result_t omapi_typed_data_new(const char *, int, omapi_typed_data_t **, omapi_datatype_t,...)
Definition: alloc.c:803
isc_result_t omapi_connection_reader(omapi_object_t *)
Definition: buffer.c:131
const char int line
Definition: dhcpd.h:3802
isc_result_t omapi_connection_sign_data(int mode, dst_key_t *key, void **context, const unsigned char *data, const unsigned len, omapi_typed_data_t **result)
Definition: connection.c:808
Definition: data.h:205
omapi_object_type_t * omapi_type_connection
Definition: support.c:33
isc_result_t omapi_register_io_object(omapi_object_t *, int(*)(omapi_object_t *), int(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *), isc_result_t(*)(omapi_object_t *))
Definition: dispatch.c:198
isc_result_t omapi_make_int_value(omapi_value_t **, omapi_data_string_t *, int, const char *, int)
Definition: support.c:709
isc_result_t omapi_buffer_dereference(omapi_buffer_t **, const char *, int)
Definition: alloc.c:766
isc_result_t omapi_object_reference(omapi_object_t **, omapi_object_t *, const char *, int)
Definition: alloc.c:571
#define SIG_MODE_INIT
Definition: omapip_p.h:73
#define MDL
Definition: omapip.h:567
dhcp_context_t dhcp_gbl_ctx
Definition: isclib.c:33
#define DHCP_R_NOTYET
Definition: result.h:50
#define DHCP_R_INVALIDARG
Definition: result.h:49
omapi_typed_data_t * value
Definition: omapip.h:90
int int int log_debug(const char *,...) __attribute__((__format__(__printf__
omapi_buffer_t * outbufs
Definition: omapip_p.h:194
isc_result_t omapi_signal_in(omapi_object_t *, const char *,...)
Definition: support.c:285
int trace_playback(void)
int log_error(const char *,...) __attribute__((__format__(__printf__
omapi_datatype_t type
Definition: omapip.h:50
#define DHCP_R_HOSTUNKNOWN
Definition: result.h:46
omapi_buffer_t * inbufs
Definition: omapip_p.h:192
void omapi_connection_trace_setup(void)
isc_mem_t * mctx
Definition: isclib.h:95
struct omapi_typed_data_t::@3::@4 buffer
#define SHUT_RD
Definition: osdep.h:276
isc_result_t omapi_connection_output_auth_length(omapi_object_t *h, unsigned *l)
Definition: connection.c:876
isc_result_t omapi_get_value_str(omapi_object_t *, omapi_object_t *, const char *, omapi_value_t **)
Definition: support.c:482
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)
Definition: connection.c:891
OMAPI_OBJECT_ALLOC(omapi_connection, omapi_connection_object_t, omapi_type_connection)
Definition: connection.c:50
isc_result_t omapi_addr_list_reference(omapi_addr_list_t **, omapi_addr_list_t *, const char *, int)
Definition: alloc.c:1120
trace_type_t * trace_type_register(const char *, void *, void(*)(trace_type_t *, unsigned, char *), void(*)(trace_type_t *), const char *, int)
void trace_stop(void)
unsigned len
Definition: trace.h:76
isc_result_t omapi_connection_writer(omapi_object_t *)
Definition: buffer.c:448
isc_result_t omapi_connect_list(omapi_object_t *c, omapi_addr_list_t *remote_addrs, omapi_addr_t *local_addr)
Definition: connection.c:104
isc_result_t omapi_object_dereference(omapi_object_t **, const char *, int)
Definition: alloc.c:593
isc_result_t omapi_signal(omapi_object_t *, const char *,...)
Definition: support.c:267
isc_result_t trace_write_packet_iov(trace_type_t *, int, trace_iov_t *, const char *, int)
isc_result_t omapi_connection_reaper(omapi_object_t *h)
Definition: connection.c:744
isc_result_t omapi_connection_require(omapi_object_t *h, unsigned bytes)
Definition: connection.c:563
void dfree(void *, const char *, int)
Definition: alloc.c:145
isc_result_t omapi_make_value(omapi_value_t **, omapi_data_string_t *, omapi_typed_data_t *, const char *, int)
Definition: support.c:651
union omapi_typed_data_t::@3 u
void omapi_connection_register(omapi_connection_object_t *, const char *, int)
isc_result_t omapi_addr_list_dereference(omapi_addr_list_t **, const char *, int)
Definition: alloc.c:1142
isc_result_t uerr2isc(int)
Definition: toisc.c:37
int trace_record(void)
void * dmalloc(size_t, const char *, int)
Definition: alloc.c:57
#define ISC_R_SUCCESS
isc_result_t omapi_connect(omapi_object_t *, const char *, unsigned)
isc_result_t omapi_typed_data_reference(omapi_typed_data_t **, omapi_typed_data_t *, const char *, int)
Definition: alloc.c:880
void cleanup(void)
isc_result_t omapi_value_dereference(omapi_value_t **, const char *, int)
Definition: alloc.c:1060
isc_result_t omapi_connection_stuff_values(omapi_object_t *c, omapi_object_t *id, omapi_object_t *m)
Definition: connection.c:1074
isc_result_t isclib_make_dst_key(char *inname, char *algorithm, unsigned char *secret, int length, dst_key_t **dstkey)
Definition: isclib.c:332
isc_result_t omapi_connection_get_value(omapi_object_t *h, omapi_object_t *id, omapi_data_string_t *name, omapi_value_t **value)
Definition: connection.c:960
int omapi_ds_strcmp(omapi_data_string_t *, const char *)
Definition: support.c:581
isc_result_t omapi_connection_connect(omapi_object_t *h)
Definition: connection.c:606
isc_result_t omapi_unregister_io_object(omapi_object_t *)
Definition: dispatch.c:355
#define omapi_array_foreach_end(array, stype, var)
Definition: omapip.h:256
isc_result_t omapi_connection_signal_handler(omapi_object_t *h, const char *name, va_list ap)
Definition: connection.c:1055
#define SIG_MODE_FINAL
Definition: omapip_p.h:75
isc_result_t omapi_listener_connect(omapi_connection_object_t **obj, omapi_listener_object_t *listener, int socket, struct sockaddr_in *remote_addr)
Definition: listener.c:278
#define OMAPI_ARRAY_TYPE(name, stype)
Definition: omapip.h:197
#define DHCP_R_INCOMPLETE
Definition: result.h:58
const char * file
Definition: dhcpd.h:3802
int omapi_connection_readfd(omapi_object_t *h)
Definition: connection.c:580
isc_result_t trace_write_packet(trace_type_t *, unsigned, const char *, const char *, int)
int omapi_connection_writefd(omapi_object_t *h)
Definition: connection.c:597
isc_result_t omapi_connection_destroy(omapi_object_t *h, const char *file, int line)
Definition: connection.c:1034
isc_result_t omapi_typed_data_dereference(omapi_typed_data_t **, const char *, int)
Definition: alloc.c:901
#define omapi_array_foreach_begin(array, stype, var)
Definition: omapip.h:242
isc_result_t omapi_addr_list_new(omapi_addr_list_t **, unsigned, const char *, int)
Definition: alloc.c:1104