00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "dhcpd.h"
00031
00032 #include <omapip/omapip_p.h>
00033 #include <arpa/inet.h>
00034 #include <arpa/nameser.h>
00035 #include <errno.h>
00036
00037 #if defined (TRACING)
00038 static void trace_connect_input (trace_type_t *, unsigned, char *);
00039 static void trace_connect_stop (trace_type_t *);
00040 static void trace_disconnect_input (trace_type_t *, unsigned, char *);
00041 static void trace_disconnect_stop (trace_type_t *);
00042 trace_type_t *trace_connect;
00043 trace_type_t *trace_disconnect;
00044 extern omapi_array_t *trace_listeners;
00045 #endif
00046 static isc_result_t omapi_connection_connect_internal (omapi_object_t *);
00047
00048 OMAPI_OBJECT_ALLOC (omapi_connection,
00049 omapi_connection_object_t, omapi_type_connection)
00050
00051 isc_result_t omapi_connect (omapi_object_t *c,
00052 const char *server_name,
00053 unsigned port)
00054 {
00055 struct hostent *he;
00056 unsigned i, hix;
00057 omapi_addr_list_t *addrs = (omapi_addr_list_t *)0;
00058 struct in_addr foo;
00059 isc_result_t status;
00060
00061 #ifdef DEBUG_PROTOCOL
00062 log_debug ("omapi_connect(%s, port=%d)", server_name, port);
00063 #endif
00064
00065 if (!inet_aton (server_name, &foo)) {
00066
00067
00068 he = gethostbyname (server_name);
00069 if (!he)
00070 return DHCP_R_HOSTUNKNOWN;
00071 for (i = 0; he -> h_addr_list [i]; i++)
00072 ;
00073 if (i == 0)
00074 return DHCP_R_HOSTUNKNOWN;
00075 hix = i;
00076
00077 status = omapi_addr_list_new (&addrs, hix, MDL);
00078 if (status != ISC_R_SUCCESS)
00079 return status;
00080 for (i = 0; i < hix; i++) {
00081 addrs -> addresses [i].addrtype = he -> h_addrtype;
00082 addrs -> addresses [i].addrlen = he -> h_length;
00083 memcpy (addrs -> addresses [i].address,
00084 he -> h_addr_list [i],
00085 (unsigned)he -> h_length);
00086 addrs -> addresses [i].port = port;
00087 }
00088 } else {
00089 status = omapi_addr_list_new (&addrs, 1, MDL);
00090 if (status != ISC_R_SUCCESS)
00091 return status;
00092 addrs -> addresses [0].addrtype = AF_INET;
00093 addrs -> addresses [0].addrlen = sizeof foo;
00094 memcpy (addrs -> addresses [0].address, &foo, sizeof foo);
00095 addrs -> addresses [0].port = port;
00096 }
00097 status = omapi_connect_list (c, addrs, (omapi_addr_t *)0);
00098 omapi_addr_list_dereference (&addrs, MDL);
00099 return status;
00100 }
00101
00102 isc_result_t omapi_connect_list (omapi_object_t *c,
00103 omapi_addr_list_t *remote_addrs,
00104 omapi_addr_t *local_addr)
00105 {
00106 isc_result_t status;
00107 omapi_connection_object_t *obj;
00108 int flag;
00109 struct sockaddr_in local_sin;
00110
00111 obj = (omapi_connection_object_t *)0;
00112 status = omapi_connection_allocate (&obj, MDL);
00113 if (status != ISC_R_SUCCESS)
00114 return status;
00115
00116 status = omapi_object_reference (&c -> outer, (omapi_object_t *)obj,
00117 MDL);
00118 if (status != ISC_R_SUCCESS) {
00119 omapi_connection_dereference (&obj, MDL);
00120 return status;
00121 }
00122 status = omapi_object_reference (&obj -> inner, c, MDL);
00123 if (status != ISC_R_SUCCESS) {
00124 omapi_connection_dereference (&obj, MDL);
00125 return status;
00126 }
00127
00128
00129 omapi_addr_list_reference (&obj -> connect_list, remote_addrs, MDL);
00130 obj -> cptr = 0;
00131 obj -> state = omapi_connection_unconnected;
00132
00133 #if defined (TRACING)
00134
00135
00136 if (!trace_playback ()) {
00137 #endif
00138
00139 obj -> socket =
00140 socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
00141 if (obj -> socket < 0) {
00142 omapi_connection_dereference (&obj, MDL);
00143 if (errno == EMFILE || errno == ENFILE
00144 || errno == ENOBUFS)
00145 return ISC_R_NORESOURCES;
00146 return ISC_R_UNEXPECTED;
00147 }
00148
00149
00150 if (local_addr) {
00151
00152 if (local_addr -> addrtype != AF_INET) {
00153 omapi_connection_dereference (&obj, MDL);
00154 return DHCP_R_INVALIDARG;
00155 }
00156 local_sin.sin_port = htons (local_addr -> port);
00157 memcpy (&local_sin.sin_addr,
00158 local_addr -> address,
00159 local_addr -> addrlen);
00160 #if defined (HAVE_SA_LEN)
00161 local_sin.sin_len = sizeof local_addr;
00162 #endif
00163 local_sin.sin_family = AF_INET;
00164 memset (&local_sin.sin_zero, 0,
00165 sizeof local_sin.sin_zero);
00166
00167 if (bind (obj -> socket, (struct sockaddr *)&local_sin,
00168 sizeof local_sin) < 0) {
00169 omapi_connection_object_t **objp = &obj;
00170 omapi_object_t **o = (omapi_object_t **)objp;
00171 omapi_object_dereference(o, MDL);
00172 if (errno == EADDRINUSE)
00173 return ISC_R_ADDRINUSE;
00174 if (errno == EADDRNOTAVAIL)
00175 return ISC_R_ADDRNOTAVAIL;
00176 if (errno == EACCES)
00177 return ISC_R_NOPERM;
00178 return ISC_R_UNEXPECTED;
00179 }
00180 obj -> local_addr = local_sin;
00181 }
00182
00183 #if defined(F_SETFD)
00184 if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
00185 close (obj -> socket);
00186 omapi_connection_dereference (&obj, MDL);
00187 return ISC_R_UNEXPECTED;
00188 }
00189 #endif
00190
00191
00192 flag = 1;
00193 if (setsockopt (obj -> socket, SOL_SOCKET, SO_REUSEADDR,
00194 (char *)&flag, sizeof flag) < 0) {
00195 omapi_connection_dereference (&obj, MDL);
00196 return ISC_R_UNEXPECTED;
00197 }
00198
00199
00200 if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
00201 omapi_connection_dereference (&obj, MDL);
00202 return ISC_R_UNEXPECTED;
00203 }
00204
00205 #ifdef SO_NOSIGPIPE
00206
00207
00208
00209
00210 flag = 1;
00211 if (setsockopt(obj->socket, SOL_SOCKET, SO_NOSIGPIPE,
00212 (char *)&flag, sizeof(flag)) < 0) {
00213 omapi_connection_dereference (&obj, MDL);
00214 return ISC_R_UNEXPECTED;
00215 }
00216 #endif
00217
00218 status = (omapi_register_io_object
00219 ((omapi_object_t *)obj,
00220 0, omapi_connection_writefd,
00221 0, omapi_connection_connect,
00222 omapi_connection_reaper));
00223 if (status != ISC_R_SUCCESS)
00224 goto out;
00225 status = omapi_connection_connect_internal ((omapi_object_t *)
00226 obj);
00227
00228
00229
00230
00231
00232
00233
00234 if (status == ISC_R_INPROGRESS) {
00235 status = ISC_R_SUCCESS;
00236 }
00237 #if defined (TRACING)
00238 }
00239 omapi_connection_register (obj, MDL);
00240 #endif
00241
00242 out:
00243 omapi_connection_dereference (&obj, MDL);
00244 return status;
00245 }
00246
00247 #if defined (TRACING)
00248 omapi_array_t *omapi_connections;
00249
00250 OMAPI_ARRAY_TYPE(omapi_connection, omapi_connection_object_t)
00251
00252 void omapi_connection_trace_setup (void) {
00253 trace_connect = trace_type_register ("connect", (void *)0,
00254 trace_connect_input,
00255 trace_connect_stop, MDL);
00256 trace_disconnect = trace_type_register ("disconnect", (void *)0,
00257 trace_disconnect_input,
00258 trace_disconnect_stop, MDL);
00259 }
00260
00261 void omapi_connection_register (omapi_connection_object_t *obj,
00262 const char *file, int line)
00263 {
00264 isc_result_t status;
00265 trace_iov_t iov [6];
00266 int iov_count = 0;
00267 int32_t connect_index, listener_index;
00268 static int32_t index;
00269
00270 if (!omapi_connections) {
00271 status = omapi_connection_array_allocate (&omapi_connections,
00272 file, line);
00273 if (status != ISC_R_SUCCESS)
00274 return;
00275 }
00276
00277 status = omapi_connection_array_extend (omapi_connections, obj,
00278 (int *)0, file, line);
00279 if (status != ISC_R_SUCCESS) {
00280 obj -> index = -1;
00281 return;
00282 }
00283
00284 #if defined (TRACING)
00285 if (trace_record ()) {
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295 connect_index = htonl (index);
00296 index++;
00297 if (obj -> listener)
00298 listener_index = htonl (obj -> listener -> index);
00299 else
00300 listener_index = htonl (-1);
00301 iov [iov_count].buf = (char *)&connect_index;
00302 iov [iov_count++].len = sizeof connect_index;
00303 iov [iov_count].buf = (char *)&listener_index;
00304 iov [iov_count++].len = sizeof listener_index;
00305 iov [iov_count].buf = (char *)&obj -> remote_addr.sin_port;
00306 iov [iov_count++].len = sizeof obj -> remote_addr.sin_port;
00307 iov [iov_count].buf = (char *)&obj -> local_addr.sin_port;
00308 iov [iov_count++].len = sizeof obj -> local_addr.sin_port;
00309 iov [iov_count].buf = (char *)&obj -> remote_addr.sin_addr;
00310 iov [iov_count++].len = sizeof obj -> remote_addr.sin_addr;
00311 iov [iov_count].buf = (char *)&obj -> local_addr.sin_addr;
00312 iov [iov_count++].len = sizeof obj -> local_addr.sin_addr;
00313
00314 status = trace_write_packet_iov (trace_connect,
00315 iov_count, iov, file, line);
00316 }
00317 #endif
00318 }
00319
00320 static void trace_connect_input (trace_type_t *ttype,
00321 unsigned length, char *buf)
00322 {
00323 struct sockaddr_in remote, local;
00324 int32_t connect_index, listener_index;
00325 char *s = buf;
00326 omapi_connection_object_t *obj;
00327 isc_result_t status;
00328 int i;
00329
00330 if (length != ((sizeof connect_index) +
00331 (sizeof remote.sin_port) +
00332 (sizeof remote.sin_addr)) * 2) {
00333 log_error ("Trace connect: invalid length %d", length);
00334 return;
00335 }
00336
00337 memset (&remote, 0, sizeof remote);
00338 memset (&local, 0, sizeof local);
00339 memcpy (&connect_index, s, sizeof connect_index);
00340 s += sizeof connect_index;
00341 memcpy (&listener_index, s, sizeof listener_index);
00342 s += sizeof listener_index;
00343 memcpy (&remote.sin_port, s, sizeof remote.sin_port);
00344 s += sizeof remote.sin_port;
00345 memcpy (&local.sin_port, s, sizeof local.sin_port);
00346 s += sizeof local.sin_port;
00347 memcpy (&remote.sin_addr, s, sizeof remote.sin_addr);
00348 s += sizeof remote.sin_addr;
00349 memcpy (&local.sin_addr, s, sizeof local.sin_addr);
00350 s += sizeof local.sin_addr;
00351 POST(s);
00352
00353 connect_index = ntohl (connect_index);
00354 listener_index = ntohl (listener_index);
00355
00356
00357
00358 if (listener_index != -1) {
00359 omapi_listener_object_t *listener;
00360 listener = (omapi_listener_object_t *)0;
00361 omapi_array_foreach_begin (trace_listeners,
00362 omapi_listener_object_t, lp) {
00363 if (lp -> address.sin_port == local.sin_port) {
00364 omapi_listener_reference (&listener, lp, MDL);
00365 omapi_listener_dereference (&lp, MDL);
00366 break;
00367 }
00368 } omapi_array_foreach_end (trace_listeners,
00369 omapi_listener_object_t, lp);
00370 if (!listener) {
00371 log_error ("%s%ld, addr %s, port %d",
00372 "Spurious traced listener connect - index ",
00373 (long int)listener_index,
00374 inet_ntoa (local.sin_addr),
00375 ntohs (local.sin_port));
00376 return;
00377 }
00378 obj = (omapi_connection_object_t *)0;
00379 status = omapi_listener_connect (&obj, listener, -1, &remote);
00380 if (status != ISC_R_SUCCESS) {
00381 log_error ("traced listener connect: %s",
00382 isc_result_totext (status));
00383 }
00384 if (obj)
00385 omapi_connection_dereference (&obj, MDL);
00386 omapi_listener_dereference (&listener, MDL);
00387 return;
00388 }
00389
00390
00391 omapi_array_foreach_begin (omapi_connections,
00392 omapi_connection_object_t, lp) {
00393 for (i = 0; (lp->connect_list &&
00394 i < lp->connect_list->count); i++) {
00395 if (!memcmp (&remote.sin_addr,
00396 &lp->connect_list->addresses[i].address,
00397 sizeof remote.sin_addr) &&
00398 (ntohs (remote.sin_port) ==
00399 lp->connect_list->addresses[i].port)) {
00400 lp->state = omapi_connection_connected;
00401 lp->remote_addr = remote;
00402 lp->remote_addr.sin_family = AF_INET;
00403 omapi_addr_list_dereference(&lp->connect_list, MDL);
00404 lp->index = connect_index;
00405 status = omapi_signal_in((omapi_object_t *)lp,
00406 "connect");
00407 omapi_connection_dereference (&lp, MDL);
00408 return;
00409 }
00410 }
00411 } omapi_array_foreach_end (omapi_connections,
00412 omapi_connection_object_t, lp);
00413
00414 log_error ("Spurious traced connect - index %ld, addr %s, port %d",
00415 (long int)connect_index, inet_ntoa (remote.sin_addr),
00416 ntohs (remote.sin_port));
00417 return;
00418 }
00419
00420 static void trace_connect_stop (trace_type_t *ttype) { }
00421
00422 static void trace_disconnect_input (trace_type_t *ttype,
00423 unsigned length, char *buf)
00424 {
00425 int32_t *index;
00426 if (length != sizeof *index) {
00427 log_error ("trace disconnect: wrong length %d", length);
00428 return;
00429 }
00430
00431 index = (int32_t *)buf;
00432
00433 omapi_array_foreach_begin (omapi_connections,
00434 omapi_connection_object_t, lp) {
00435 if (lp -> index == ntohl (*index)) {
00436 omapi_disconnect ((omapi_object_t *)lp, 1);
00437 omapi_connection_dereference (&lp, MDL);
00438 return;
00439 }
00440 } omapi_array_foreach_end (omapi_connections,
00441 omapi_connection_object_t, lp);
00442
00443 log_error ("trace disconnect: no connection matching index %ld",
00444 (long int)ntohl (*index));
00445 }
00446
00447 static void trace_disconnect_stop (trace_type_t *ttype) { }
00448 #endif
00449
00450
00451
00452
00453
00454 isc_result_t omapi_disconnect (omapi_object_t *h,
00455 int force)
00456 {
00457 omapi_connection_object_t *c;
00458
00459 #ifdef DEBUG_PROTOCOL
00460 log_debug ("omapi_disconnect(%s)", force ? "force" : "");
00461 #endif
00462
00463 c = (omapi_connection_object_t *)h;
00464 if (c -> type != omapi_type_connection)
00465 return DHCP_R_INVALIDARG;
00466
00467 #if defined (TRACING)
00468 if (trace_record ()) {
00469 isc_result_t status;
00470 int32_t index;
00471
00472 index = htonl (c -> index);
00473 status = trace_write_packet (trace_disconnect,
00474 sizeof index, (char *)&index,
00475 MDL);
00476 if (status != ISC_R_SUCCESS) {
00477 trace_stop ();
00478 log_error ("trace_write_packet: %s",
00479 isc_result_totext (status));
00480 }
00481 }
00482 if (!trace_playback ()) {
00483 #endif
00484 if (!force) {
00485
00486
00487 if (c -> state == omapi_connection_disconnecting)
00488 return ISC_R_SUCCESS;
00489
00490
00491
00492
00493
00494
00495 if (!shutdown (c -> socket, SHUT_RD)) {
00496 if (c -> out_bytes > 0) {
00497 c -> state =
00498 omapi_connection_disconnecting;
00499 return ISC_R_SUCCESS;
00500 }
00501 }
00502 }
00503 close (c -> socket);
00504 #if defined (TRACING)
00505 }
00506 #endif
00507 c -> state = omapi_connection_closed;
00508
00509 #if 0
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520 if (h -> outer) {
00521 if (h -> outer -> inner)
00522 omapi_object_dereference (&h -> outer -> inner, MDL);
00523 omapi_object_dereference (&h -> outer, MDL);
00524 }
00525 #else
00526 if (h->outer) {
00527 omapi_unregister_io_object(h);
00528 }
00529 #endif
00530
00531
00532
00533 omapi_signal (h, "disconnect", h);
00534
00535
00536 if (h->inner != NULL) {
00537 if (h->inner->outer != NULL) {
00538 omapi_object_dereference(&h->inner->outer, MDL);
00539 }
00540 omapi_object_dereference(&h->inner, MDL);
00541 }
00542
00543
00544
00545
00546
00547 if (c->inbufs != NULL) {
00548 omapi_buffer_dereference(&c->inbufs, MDL);
00549 }
00550 c->in_bytes = 0;
00551 if (c->outbufs != NULL) {
00552 omapi_buffer_dereference(&c->outbufs, MDL);
00553 }
00554 c->out_bytes = 0;
00555
00556 return ISC_R_SUCCESS;
00557 }
00558
00559 isc_result_t omapi_connection_require (omapi_object_t *h, unsigned bytes)
00560 {
00561 omapi_connection_object_t *c;
00562
00563 if (h -> type != omapi_type_connection)
00564 return DHCP_R_INVALIDARG;
00565 c = (omapi_connection_object_t *)h;
00566
00567 c -> bytes_needed = bytes;
00568 if (c -> bytes_needed <= c -> in_bytes) {
00569 return ISC_R_SUCCESS;
00570 }
00571 return DHCP_R_NOTYET;
00572 }
00573
00574
00575
00576 int omapi_connection_readfd (omapi_object_t *h)
00577 {
00578 omapi_connection_object_t *c;
00579 if (h -> type != omapi_type_connection)
00580 return -1;
00581 c = (omapi_connection_object_t *)h;
00582 if (c -> state != omapi_connection_connected)
00583 return -1;
00584 return c -> socket;
00585 }
00586
00587
00588
00589
00590
00591
00592
00593 int omapi_connection_writefd (omapi_object_t *h)
00594 {
00595 omapi_connection_object_t *c;
00596 if (h -> type != omapi_type_connection)
00597 return -1;
00598 c = (omapi_connection_object_t *)h;
00599 return c->socket;
00600 }
00601
00602 isc_result_t omapi_connection_connect (omapi_object_t *h)
00603 {
00604 isc_result_t status;
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614 status = omapi_connection_connect_internal (h);
00615 if (status == ISC_R_INPROGRESS)
00616 return ISC_R_INPROGRESS;
00617
00618 if (status != ISC_R_SUCCESS)
00619 omapi_signal (h, "status", status);
00620
00621 return ISC_R_SUCCESS;
00622 }
00623
00624 static isc_result_t omapi_connection_connect_internal (omapi_object_t *h)
00625 {
00626 int error = 0;
00627 omapi_connection_object_t *c;
00628 socklen_t sl;
00629 isc_result_t status;
00630
00631 if (h -> type != omapi_type_connection)
00632 return DHCP_R_INVALIDARG;
00633 c = (omapi_connection_object_t *)h;
00634
00635 if (c -> state == omapi_connection_connecting) {
00636 sl = sizeof error;
00637 if (getsockopt (c -> socket, SOL_SOCKET, SO_ERROR,
00638 (char *)&error, &sl) < 0) {
00639 omapi_disconnect (h, 1);
00640 return ISC_R_SUCCESS;
00641 }
00642 if (!error)
00643 c -> state = omapi_connection_connected;
00644 }
00645 if (c -> state == omapi_connection_connecting ||
00646 c -> state == omapi_connection_unconnected) {
00647 if (c -> cptr >= c -> connect_list -> count) {
00648 switch (error) {
00649 case ECONNREFUSED:
00650 status = ISC_R_CONNREFUSED;
00651 break;
00652 case ENETUNREACH:
00653 status = ISC_R_NETUNREACH;
00654 break;
00655 default:
00656 status = uerr2isc (error);
00657 break;
00658 }
00659 omapi_disconnect (h, 1);
00660 return status;
00661 }
00662
00663 if (c -> connect_list -> addresses [c -> cptr].addrtype !=
00664 AF_INET) {
00665 omapi_disconnect (h, 1);
00666 return DHCP_R_INVALIDARG;
00667 }
00668
00669 memcpy (&c -> remote_addr.sin_addr,
00670 &c -> connect_list -> addresses [c -> cptr].address,
00671 sizeof c -> remote_addr.sin_addr);
00672 c -> remote_addr.sin_family = AF_INET;
00673 c -> remote_addr.sin_port =
00674 htons (c -> connect_list -> addresses [c -> cptr].port);
00675 #if defined (HAVE_SA_LEN)
00676 c -> remote_addr.sin_len = sizeof c -> remote_addr;
00677 #endif
00678 memset (&c -> remote_addr.sin_zero, 0,
00679 sizeof c -> remote_addr.sin_zero);
00680 ++c -> cptr;
00681
00682 error = connect (c -> socket,
00683 (struct sockaddr *)&c -> remote_addr,
00684 sizeof c -> remote_addr);
00685 if (error < 0) {
00686 error = errno;
00687 if (error != EINPROGRESS) {
00688 omapi_disconnect (h, 1);
00689 switch (error) {
00690 case ECONNREFUSED:
00691 status = ISC_R_CONNREFUSED;
00692 break;
00693 case ENETUNREACH:
00694 status = ISC_R_NETUNREACH;
00695 break;
00696 default:
00697 status = uerr2isc (error);
00698 break;
00699 }
00700 return status;
00701 }
00702 c -> state = omapi_connection_connecting;
00703 return DHCP_R_INCOMPLETE;
00704 }
00705 c -> state = omapi_connection_connected;
00706 }
00707
00708
00709
00710 sl = sizeof (c -> local_addr);
00711 if (getsockname (c -> socket,
00712 (struct sockaddr *)&c -> local_addr, &sl) < 0) {
00713 }
00714
00715
00716
00717
00718
00719 status = omapi_reregister_io_object (h,
00720 omapi_connection_readfd,
00721 omapi_connection_writefd,
00722 omapi_connection_reader,
00723 omapi_connection_writer,
00724 omapi_connection_reaper);
00725
00726 if (status != ISC_R_SUCCESS) {
00727 omapi_disconnect (h, 1);
00728 return status;
00729 }
00730
00731 omapi_signal_in (h, "connect");
00732 omapi_addr_list_dereference (&c -> connect_list, MDL);
00733 return ISC_R_INPROGRESS;
00734 }
00735
00736
00737
00738
00739
00740 isc_result_t omapi_connection_reaper (omapi_object_t *h)
00741 {
00742 omapi_connection_object_t *c;
00743
00744 if (h -> type != omapi_type_connection)
00745 return DHCP_R_INVALIDARG;
00746
00747 c = (omapi_connection_object_t *)h;
00748 if (c -> state == omapi_connection_disconnecting &&
00749 c -> out_bytes == 0) {
00750 #ifdef DEBUG_PROTOCOL
00751 log_debug ("omapi_connection_reaper(): disconnect");
00752 #endif
00753 omapi_disconnect (h, 1);
00754 }
00755 if (c -> state == omapi_connection_closed) {
00756 #ifdef DEBUG_PROTOCOL
00757 log_debug ("omapi_connection_reaper(): closed");
00758 #endif
00759 return ISC_R_NOTCONNECTED;
00760 }
00761 return ISC_R_SUCCESS;
00762 }
00763
00764 static isc_result_t make_dst_key (dst_key_t **dst_key, omapi_object_t *a) {
00765 omapi_value_t *name = (omapi_value_t *)0;
00766 omapi_value_t *algorithm = (omapi_value_t *)0;
00767 omapi_value_t *key = (omapi_value_t *)0;
00768 char *name_str = NULL;
00769 isc_result_t status = ISC_R_SUCCESS;
00770
00771 if (status == ISC_R_SUCCESS)
00772 status = omapi_get_value_str
00773 (a, (omapi_object_t *)0, "name", &name);
00774
00775 if (status == ISC_R_SUCCESS)
00776 status = omapi_get_value_str
00777 (a, (omapi_object_t *)0, "algorithm", &algorithm);
00778
00779 if (status == ISC_R_SUCCESS)
00780 status = omapi_get_value_str
00781 (a, (omapi_object_t *)0, "key", &key);
00782
00783 if (status == ISC_R_SUCCESS) {
00784 if ((algorithm->value->type != omapi_datatype_data &&
00785 algorithm->value->type != omapi_datatype_string) ||
00786 strncasecmp((char *)algorithm->value->u.buffer.value,
00787 NS_TSIG_ALG_HMAC_MD5 ".",
00788 algorithm->value->u.buffer.len) != 0) {
00789 status = DHCP_R_INVALIDARG;
00790 }
00791 }
00792
00793 if (status == ISC_R_SUCCESS) {
00794 name_str = dmalloc (name -> value -> u.buffer.len + 1, MDL);
00795 if (!name_str)
00796 status = ISC_R_NOMEMORY;
00797 }
00798
00799 if (status == ISC_R_SUCCESS) {
00800 memcpy (name_str,
00801 name -> value -> u.buffer.value,
00802 name -> value -> u.buffer.len);
00803 name_str [name -> value -> u.buffer.len] = 0;
00804
00805 status = isclib_make_dst_key(name_str,
00806 DHCP_HMAC_MD5_NAME,
00807 key->value->u.buffer.value,
00808 key->value->u.buffer.len,
00809 dst_key);
00810
00811 if (*dst_key == NULL)
00812 status = ISC_R_NOMEMORY;
00813 }
00814
00815 if (name_str)
00816 dfree (name_str, MDL);
00817 if (key)
00818 omapi_value_dereference (&key, MDL);
00819 if (algorithm)
00820 omapi_value_dereference (&algorithm, MDL);
00821 if (name)
00822 omapi_value_dereference (&name, MDL);
00823
00824 return status;
00825 }
00826
00827 isc_result_t omapi_connection_sign_data (int mode,
00828 dst_key_t *key,
00829 void **context,
00830 const unsigned char *data,
00831 const unsigned len,
00832 omapi_typed_data_t **result)
00833 {
00834 omapi_typed_data_t *td = (omapi_typed_data_t *)0;
00835 isc_result_t status;
00836 dst_context_t **dctx = (dst_context_t **)context;
00837
00838
00839 if (mode & SIG_MODE_INIT) {
00840 status = dst_context_create(key, dhcp_gbl_ctx.mctx, dctx);
00841 if (status != ISC_R_SUCCESS) {
00842 return status;
00843 }
00844 }
00845
00846
00847 if (len != 0) {
00848 isc_region_t region;
00849 region.base = (unsigned char *)data;
00850 region.length = len;
00851 dst_context_adddata(*dctx, ®ion);
00852 }
00853
00854
00855 if (mode & SIG_MODE_FINAL) {
00856 unsigned int sigsize;
00857 isc_buffer_t sigbuf;
00858
00859 status = dst_key_sigsize(key, &sigsize);
00860 if (status != ISC_R_SUCCESS) {
00861 goto cleanup;
00862 }
00863
00864 status = omapi_typed_data_new (MDL, &td,
00865 omapi_datatype_data,
00866 sigsize);
00867 if (status != ISC_R_SUCCESS) {
00868 goto cleanup;
00869 }
00870
00871 isc_buffer_init(&sigbuf, td->u.buffer.value, td->u.buffer.len);
00872 status = dst_context_sign(*dctx, &sigbuf);
00873 if (status != ISC_R_SUCCESS) {
00874 goto cleanup;
00875 }
00876
00877 if (result) {
00878 omapi_typed_data_reference (result, td, MDL);
00879 }
00880
00881 cleanup:
00882
00883
00884
00885 if (td) {
00886 omapi_typed_data_dereference (&td, MDL);
00887 }
00888 dst_context_destroy(dctx);
00889 return status;
00890 }
00891
00892 return ISC_R_SUCCESS;
00893 }
00894
00895 isc_result_t omapi_connection_output_auth_length (omapi_object_t *h,
00896 unsigned *l)
00897 {
00898 omapi_connection_object_t *c;
00899
00900 if (h->type != omapi_type_connection)
00901 return DHCP_R_INVALIDARG;
00902 c = (omapi_connection_object_t *)h;
00903
00904 if (c->out_key == NULL)
00905 return ISC_R_NOTFOUND;
00906
00907 return(dst_key_sigsize(c->out_key, l));
00908 }
00909
00910 isc_result_t omapi_connection_set_value (omapi_object_t *h,
00911 omapi_object_t *id,
00912 omapi_data_string_t *name,
00913 omapi_typed_data_t *value)
00914 {
00915 omapi_connection_object_t *c;
00916 isc_result_t status;
00917
00918 if (h -> type != omapi_type_connection)
00919 return DHCP_R_INVALIDARG;
00920 c = (omapi_connection_object_t *)h;
00921
00922 if (omapi_ds_strcmp (name, "input-authenticator") == 0) {
00923 if (value && value -> type != omapi_datatype_object)
00924 return DHCP_R_INVALIDARG;
00925
00926 if (c -> in_context) {
00927 omapi_connection_sign_data (SIG_MODE_FINAL,
00928 c -> in_key,
00929 &c -> in_context,
00930 0, 0,
00931 (omapi_typed_data_t **) 0);
00932 }
00933
00934 if (c->in_key != NULL) {
00935 dst_key_free(&c->in_key);
00936 }
00937
00938 if (value) {
00939 status = make_dst_key (&c -> in_key,
00940 value -> u.object);
00941 if (status != ISC_R_SUCCESS)
00942 return status;
00943 }
00944
00945 return ISC_R_SUCCESS;
00946 }
00947 else if (omapi_ds_strcmp (name, "output-authenticator") == 0) {
00948 if (value && value -> type != omapi_datatype_object)
00949 return DHCP_R_INVALIDARG;
00950
00951 if (c -> out_context) {
00952 omapi_connection_sign_data (SIG_MODE_FINAL,
00953 c -> out_key,
00954 &c -> out_context,
00955 0, 0,
00956 (omapi_typed_data_t **) 0);
00957 }
00958
00959 if (c->out_key != NULL) {
00960 dst_key_free(&c->out_key);
00961 }
00962
00963 if (value) {
00964 status = make_dst_key (&c -> out_key,
00965 value -> u.object);
00966 if (status != ISC_R_SUCCESS)
00967 return status;
00968 }
00969
00970 return ISC_R_SUCCESS;
00971 }
00972
00973 if (h -> inner && h -> inner -> type -> set_value)
00974 return (*(h -> inner -> type -> set_value))
00975 (h -> inner, id, name, value);
00976 return ISC_R_NOTFOUND;
00977 }
00978
00979 isc_result_t omapi_connection_get_value (omapi_object_t *h,
00980 omapi_object_t *id,
00981 omapi_data_string_t *name,
00982 omapi_value_t **value)
00983 {
00984 omapi_connection_object_t *c;
00985 omapi_typed_data_t *td = (omapi_typed_data_t *)0;
00986 isc_result_t status;
00987 unsigned int sigsize;
00988
00989 if (h -> type != omapi_type_connection)
00990 return DHCP_R_INVALIDARG;
00991 c = (omapi_connection_object_t *)h;
00992
00993 if (omapi_ds_strcmp (name, "input-signature") == 0) {
00994 if (!c -> in_key || !c -> in_context)
00995 return ISC_R_NOTFOUND;
00996
00997 status = omapi_connection_sign_data (SIG_MODE_FINAL,
00998 c -> in_key,
00999 &c -> in_context,
01000 0, 0, &td);
01001 if (status != ISC_R_SUCCESS)
01002 return status;
01003
01004 status = omapi_make_value (value, name, td, MDL);
01005 omapi_typed_data_dereference (&td, MDL);
01006 return status;
01007
01008 } else if (omapi_ds_strcmp (name, "input-signature-size") == 0) {
01009 if (c->in_key == NULL)
01010 return ISC_R_NOTFOUND;
01011
01012 status = dst_key_sigsize(c->in_key, &sigsize);
01013 if (status != ISC_R_SUCCESS) {
01014 return(status);
01015 }
01016
01017 return omapi_make_int_value(value, name, sigsize, MDL);
01018
01019 } else if (omapi_ds_strcmp (name, "output-signature") == 0) {
01020 if (!c -> out_key || !c -> out_context)
01021 return ISC_R_NOTFOUND;
01022
01023 status = omapi_connection_sign_data (SIG_MODE_FINAL,
01024 c -> out_key,
01025 &c -> out_context,
01026 0, 0, &td);
01027 if (status != ISC_R_SUCCESS)
01028 return status;
01029
01030 status = omapi_make_value (value, name, td, MDL);
01031 omapi_typed_data_dereference (&td, MDL);
01032 return status;
01033
01034 } else if (omapi_ds_strcmp (name, "output-signature-size") == 0) {
01035 if (c->out_key == NULL)
01036 return ISC_R_NOTFOUND;
01037
01038
01039 status = dst_key_sigsize(c->out_key, &sigsize);
01040 if (status != ISC_R_SUCCESS) {
01041 return(status);
01042 }
01043
01044 return omapi_make_int_value(value, name, sigsize, MDL);
01045 }
01046
01047 if (h -> inner && h -> inner -> type -> get_value)
01048 return (*(h -> inner -> type -> get_value))
01049 (h -> inner, id, name, value);
01050 return ISC_R_NOTFOUND;
01051 }
01052
01053 isc_result_t omapi_connection_destroy (omapi_object_t *h,
01054 const char *file, int line)
01055 {
01056 omapi_connection_object_t *c;
01057
01058 #ifdef DEBUG_PROTOCOL
01059 log_debug ("omapi_connection_destroy()");
01060 #endif
01061
01062 if (h -> type != omapi_type_connection)
01063 return ISC_R_UNEXPECTED;
01064 c = (omapi_connection_object_t *)(h);
01065 if (c -> state == omapi_connection_connected)
01066 omapi_disconnect (h, 1);
01067 if (c -> listener)
01068 omapi_listener_dereference (&c -> listener, file, line);
01069 if (c -> connect_list)
01070 omapi_addr_list_dereference (&c -> connect_list, file, line);
01071 return ISC_R_SUCCESS;
01072 }
01073
01074 isc_result_t omapi_connection_signal_handler (omapi_object_t *h,
01075 const char *name, va_list ap)
01076 {
01077 if (h -> type != omapi_type_connection)
01078 return DHCP_R_INVALIDARG;
01079
01080 #ifdef DEBUG_PROTOCOL
01081 log_debug ("omapi_connection_signal_handler(%s)", name);
01082 #endif
01083
01084 if (h -> inner && h -> inner -> type -> signal_handler)
01085 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
01086 name, ap);
01087 return ISC_R_NOTFOUND;
01088 }
01089
01090
01091
01092
01093 isc_result_t omapi_connection_stuff_values (omapi_object_t *c,
01094 omapi_object_t *id,
01095 omapi_object_t *m)
01096 {
01097 if (m -> type != omapi_type_connection)
01098 return DHCP_R_INVALIDARG;
01099
01100 if (m -> inner && m -> inner -> type -> stuff_values)
01101 return (*(m -> inner -> type -> stuff_values)) (c, id,
01102 m -> inner);
01103 return ISC_R_SUCCESS;
01104 }