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