admin.c revision 1.29
1/* $NetBSD: admin.c,v 1.29 2009/03/12 10:57:26 tteras Exp $ */ 2 3/* Id: admin.c,v 1.25 2006/04/06 14:31:04 manubsd Exp */ 4 5/* 6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the project nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include "config.h" 35 36#include <sys/types.h> 37#include <sys/param.h> 38#include <sys/socket.h> 39#include <sys/signal.h> 40#include <sys/stat.h> 41#include <sys/un.h> 42 43#include <net/pfkeyv2.h> 44 45#include <netinet/in.h> 46#include PATH_IPSEC_H 47 48 49#include <stdlib.h> 50#include <stdio.h> 51#include <string.h> 52#include <errno.h> 53#include <netdb.h> 54#ifdef HAVE_UNISTD_H 55#include <unistd.h> 56#endif 57#ifdef ENABLE_HYBRID 58#include <resolv.h> 59#endif 60 61#include "var.h" 62#include "misc.h" 63#include "vmbuf.h" 64#include "plog.h" 65#include "sockmisc.h" 66#include "debug.h" 67 68#include "schedule.h" 69#include "localconf.h" 70#include "remoteconf.h" 71#include "grabmyaddr.h" 72#include "isakmp_var.h" 73#include "isakmp.h" 74#include "oakley.h" 75#include "handler.h" 76#include "evt.h" 77#include "pfkey.h" 78#include "ipsec_doi.h" 79#include "policy.h" 80#include "admin.h" 81#include "admin_var.h" 82#include "isakmp_inf.h" 83#ifdef ENABLE_HYBRID 84#include "isakmp_cfg.h" 85#endif 86#include "session.h" 87#include "gcmalloc.h" 88 89#ifdef ENABLE_ADMINPORT 90char *adminsock_path = ADMINSOCK_PATH; 91uid_t adminsock_owner = 0; 92gid_t adminsock_group = 0; 93mode_t adminsock_mode = 0600; 94 95static struct sockaddr_un sunaddr; 96static int admin_process __P((int, char *)); 97static int admin_reply __P((int, struct admin_com *, int, vchar_t *)); 98 99static int 100admin_handler(ctx, fd) 101 void *ctx; 102 int fd; 103{ 104 int so2; 105 struct sockaddr_storage from; 106 socklen_t fromlen = sizeof(from); 107 struct admin_com com; 108 char *combuf = NULL; 109 int len, error = -1; 110 111 so2 = accept(lcconf->sock_admin, (struct sockaddr *)&from, &fromlen); 112 if (so2 < 0) { 113 plog(LLV_ERROR, LOCATION, NULL, 114 "failed to accept admin command: %s\n", 115 strerror(errno)); 116 return -1; 117 } 118 close_on_exec(so2); 119 120 /* get buffer length */ 121 while ((len = recv(so2, (char *)&com, sizeof(com), MSG_PEEK)) < 0) { 122 if (errno == EINTR) 123 continue; 124 plog(LLV_ERROR, LOCATION, NULL, 125 "failed to recv admin command: %s\n", 126 strerror(errno)); 127 goto end; 128 } 129 130 /* sanity check */ 131 if (len < sizeof(com)) { 132 plog(LLV_ERROR, LOCATION, NULL, 133 "invalid header length of admin command\n"); 134 goto end; 135 } 136 137 /* get buffer to receive */ 138 if ((combuf = racoon_malloc(com.ac_len)) == 0) { 139 plog(LLV_ERROR, LOCATION, NULL, 140 "failed to alloc buffer for admin command\n"); 141 goto end; 142 } 143 144 /* get real data */ 145 while ((len = recv(so2, combuf, com.ac_len, 0)) < 0) { 146 if (errno == EINTR) 147 continue; 148 plog(LLV_ERROR, LOCATION, NULL, 149 "failed to recv admin command: %s\n", 150 strerror(errno)); 151 goto end; 152 } 153 154 error = admin_process(so2, combuf); 155 156end: 157 if (error == -2) { 158 plog(LLV_DEBUG, LOCATION, NULL, 159 "[%d] admin connection established\n", so2); 160 } else { 161 (void)close(so2); 162 } 163 164 if (combuf) 165 racoon_free(combuf); 166 167 return error; 168} 169 170/* 171 * main child's process. 172 */ 173static int 174admin_process(so2, combuf) 175 int so2; 176 char *combuf; 177{ 178 struct admin_com *com = (struct admin_com *)combuf; 179 vchar_t *buf = NULL; 180 vchar_t *id = NULL; 181 vchar_t *key = NULL; 182 int idtype = 0; 183 int error = 0, l_ac_errno = 0; 184 struct evt_listener_list *event_list = NULL; 185 186 if (com->ac_cmd & ADMIN_FLAG_VERSION) 187 com->ac_cmd &= ~ADMIN_FLAG_VERSION; 188 else 189 com->ac_version = 0; 190 191 switch (com->ac_cmd) { 192 case ADMIN_RELOAD_CONF: 193 signal_handler(SIGHUP); 194 break; 195 196 case ADMIN_SHOW_SCHED: { 197 caddr_t p = NULL; 198 int len; 199 200 if (sched_dump(&p, &len) != -1) { 201 buf = vmalloc(len); 202 if (buf != NULL) 203 memcpy(buf->v, p, len); 204 else 205 l_ac_errno = ENOMEM; 206 racoon_free(p); 207 } else 208 l_ac_errno = ENOMEM; 209 break; 210 } 211 212 case ADMIN_SHOW_EVT: 213 if (com->ac_version == 0) { 214 buf = evt_dump(); 215 l_ac_errno = 0; 216 } 217 break; 218 219 case ADMIN_SHOW_SA: 220 switch (com->ac_proto) { 221 case ADMIN_PROTO_ISAKMP: 222 buf = dumpph1(); 223 if (buf == NULL) 224 l_ac_errno = ENOMEM; 225 break; 226 case ADMIN_PROTO_IPSEC: 227 case ADMIN_PROTO_AH: 228 case ADMIN_PROTO_ESP: { 229 u_int p; 230 p = admin2pfkey_proto(com->ac_proto); 231 if (p != -1) { 232 buf = pfkey_dump_sadb(p); 233 if (buf == NULL) 234 l_ac_errno = ENOMEM; 235 } else 236 l_ac_errno = EINVAL; 237 break; 238 } 239 case ADMIN_PROTO_INTERNAL: 240 default: 241 l_ac_errno = ENOTSUP; 242 break; 243 } 244 break; 245 246 case ADMIN_GET_SA_CERT: { 247 struct admin_com_indexes *ndx; 248 struct sockaddr *src, *dst; 249 struct ph1handle *iph1; 250 251 ndx = (struct admin_com_indexes *) ((caddr_t)com + sizeof(*com)); 252 src = (struct sockaddr *) &ndx->src; 253 dst = (struct sockaddr *) &ndx->dst; 254 255 if (com->ac_proto != ADMIN_PROTO_ISAKMP) { 256 l_ac_errno = ENOTSUP; 257 break; 258 } 259 260 iph1 = getph1byaddrwop(src, dst); 261 if (iph1 == NULL) { 262 l_ac_errno = ENOENT; 263 break; 264 } 265 266 if (iph1->cert_p != NULL) { 267 vchar_t tmp; 268 tmp.v = iph1->cert_p->v + 1; 269 tmp.l = iph1->cert_p->l - 1; 270 buf = vdup(&tmp); 271 } 272 break; 273 } 274 275 case ADMIN_FLUSH_SA: 276 switch (com->ac_proto) { 277 case ADMIN_PROTO_ISAKMP: 278 flushph1(); 279 break; 280 case ADMIN_PROTO_IPSEC: 281 case ADMIN_PROTO_AH: 282 case ADMIN_PROTO_ESP: 283 pfkey_flush_sadb(com->ac_proto); 284 break; 285 case ADMIN_PROTO_INTERNAL: 286 /*XXX flushph2();*/ 287 default: 288 l_ac_errno = ENOTSUP; 289 break; 290 } 291 break; 292 293 case ADMIN_DELETE_SA: { 294 struct ph1handle *iph1; 295 struct sockaddr *dst; 296 struct sockaddr *src; 297 char *loc, *rem; 298 299 src = (struct sockaddr *) 300 &((struct admin_com_indexes *) 301 ((caddr_t)com + sizeof(*com)))->src; 302 dst = (struct sockaddr *) 303 &((struct admin_com_indexes *) 304 ((caddr_t)com + sizeof(*com)))->dst; 305 306 loc = racoon_strdup(saddrwop2str(src)); 307 rem = racoon_strdup(saddrwop2str(dst)); 308 STRDUP_FATAL(loc); 309 STRDUP_FATAL(rem); 310 311 if ((iph1 = getph1byaddrwop(src, dst)) == NULL) { 312 plog(LLV_ERROR, LOCATION, NULL, 313 "phase 1 for %s -> %s not found\n", loc, rem); 314 } else { 315 if (iph1->status >= PHASE1ST_ESTABLISHED) 316 isakmp_info_send_d1(iph1); 317 purge_remote(iph1); 318 } 319 320 racoon_free(loc); 321 racoon_free(rem); 322 break; 323 } 324 325#ifdef ENABLE_HYBRID 326 case ADMIN_LOGOUT_USER: { 327 struct ph1handle *iph1; 328 char *user; 329 int found = 0; 330 331 if (com->ac_len > sizeof(com) + LOGINLEN + 1) { 332 plog(LLV_ERROR, LOCATION, NULL, 333 "malformed message (login too long)\n"); 334 break; 335 } 336 337 user = (char *)(com + 1); 338 found = purgeph1bylogin(user); 339 plog(LLV_INFO, LOCATION, NULL, 340 "deleted %d SA for user \"%s\"\n", found, user); 341 342 break; 343 } 344#endif 345 346 case ADMIN_DELETE_ALL_SA_DST: { 347 struct ph1handle *iph1; 348 struct sockaddr *dst; 349 char *loc, *rem; 350 351 dst = (struct sockaddr *) 352 &((struct admin_com_indexes *) 353 ((caddr_t)com + sizeof(*com)))->dst; 354 355 rem = racoon_strdup(saddrwop2str(dst)); 356 STRDUP_FATAL(rem); 357 358 plog(LLV_INFO, LOCATION, NULL, 359 "Flushing all SAs for peer %s\n", rem); 360 361 while ((iph1 = getph1bydstaddrwop(dst)) != NULL) { 362 loc = racoon_strdup(saddrwop2str(iph1->local)); 363 STRDUP_FATAL(loc); 364 365 if (iph1->status >= PHASE1ST_ESTABLISHED) 366 isakmp_info_send_d1(iph1); 367 purge_remote(iph1); 368 369 racoon_free(loc); 370 } 371 372 racoon_free(rem); 373 break; 374 } 375 376 case ADMIN_ESTABLISH_SA_PSK: { 377 struct admin_com_psk *acp; 378 char *data; 379 380 acp = (struct admin_com_psk *) 381 ((char *)com + sizeof(*com) + 382 sizeof(struct admin_com_indexes)); 383 384 idtype = acp->id_type; 385 386 if ((id = vmalloc(acp->id_len)) == NULL) { 387 plog(LLV_ERROR, LOCATION, NULL, 388 "cannot allocate memory: %s\n", 389 strerror(errno)); 390 break; 391 } 392 data = (char *)(acp + 1); 393 memcpy(id->v, data, id->l); 394 395 if ((key = vmalloc(acp->key_len)) == NULL) { 396 plog(LLV_ERROR, LOCATION, NULL, 397 "cannot allocate memory: %s\n", 398 strerror(errno)); 399 vfree(id); 400 id = NULL; 401 break; 402 } 403 data = (char *)(data + acp->id_len); 404 memcpy(key->v, data, key->l); 405 } 406 /* FALLTHROUGH */ 407 case ADMIN_ESTABLISH_SA: { 408 struct admin_com_indexes *ndx; 409 struct sockaddr *dst; 410 struct sockaddr *src; 411 char *name = NULL; 412 413 ndx = (struct admin_com_indexes *) ((caddr_t)com + sizeof(*com)); 414 src = (struct sockaddr *) &ndx->src; 415 dst = (struct sockaddr *) &ndx->dst; 416 417 if (com->ac_cmd == ADMIN_ESTABLISH_SA && 418 com->ac_len > sizeof(*com) + sizeof(*ndx)) 419 name = (char *) ((caddr_t) ndx + sizeof(*ndx)); 420 421 switch (com->ac_proto) { 422 case ADMIN_PROTO_ISAKMP: { 423 struct ph1handle *ph1; 424 struct remoteconf *rmconf; 425 u_int16_t port; 426 427 l_ac_errno = -1; 428 429 /* connected already? */ 430 ph1 = getph1byaddrwop(src, dst); 431 if (ph1 != NULL) { 432 event_list = &ph1->evt_listeners; 433 if (ph1->status == PHASE1ST_ESTABLISHED) 434 l_ac_errno = EEXIST; 435 else 436 l_ac_errno = 0; 437 break; 438 } 439 440 /* search appropreate configuration */ 441 if (name == NULL) 442 rmconf = getrmconf(dst, 0); 443 else 444 rmconf = getrmconf_by_name(name); 445 if (rmconf == NULL) { 446 plog(LLV_ERROR, LOCATION, NULL, 447 "no configuration found " 448 "for %s\n", saddrwop2str(dst)); 449 break; 450 } 451 452#ifdef ENABLE_HYBRID 453 /* XXX This overwrites rmconf information globally. */ 454 /* Set the id and key */ 455 if (id && key) { 456 if (xauth_rmconf_used(&rmconf->xauth) == -1) 457 break; 458 459 if (rmconf->xauth->login != NULL) { 460 vfree(rmconf->xauth->login); 461 rmconf->xauth->login = NULL; 462 } 463 if (rmconf->xauth->pass != NULL) { 464 vfree(rmconf->xauth->pass); 465 rmconf->xauth->pass = NULL; 466 } 467 468 rmconf->xauth->login = id; 469 rmconf->xauth->pass = key; 470 } 471#endif 472 473 plog(LLV_INFO, LOCATION, NULL, 474 "accept a request to establish IKE-SA: " 475 "%s\n", saddrwop2str(dst)); 476 477 /* begin ident mode */ 478 ph1 = isakmp_ph1begin_i(rmconf, dst, src); 479 if (ph1 == NULL) 480 break; 481 482 event_list = &ph1->evt_listeners; 483 l_ac_errno = 0; 484 break; 485 } 486 case ADMIN_PROTO_AH: 487 case ADMIN_PROTO_ESP: { 488 struct ph2handle *iph2; 489 struct secpolicy *sp_out = NULL, *sp_in = NULL; 490 struct policyindex spidx; 491 492 l_ac_errno = -1; 493 494 /* got outbound policy */ 495 memset(&spidx, 0, sizeof(spidx)); 496 spidx.dir = IPSEC_DIR_OUTBOUND; 497 memcpy(&spidx.src, src, sizeof(spidx.src)); 498 memcpy(&spidx.dst, dst, sizeof(spidx.dst)); 499 spidx.prefs = ndx->prefs; 500 spidx.prefd = ndx->prefd; 501 spidx.ul_proto = ndx->ul_proto; 502 503 sp_out = getsp_r(&spidx); 504 if (sp_out) { 505 plog(LLV_DEBUG, LOCATION, NULL, 506 "suitable outbound SP found: %s.\n", 507 spidx2str(&sp_out->spidx)); 508 } else { 509 l_ac_errno = ENOENT; 510 plog(LLV_NOTIFY, LOCATION, NULL, 511 "no outbound policy found: %s\n", 512 spidx2str(&spidx)); 513 break; 514 } 515 516 iph2 = getph2byid(src, dst, sp_out->id); 517 if (iph2 != NULL) { 518 event_list = &iph2->evt_listeners; 519 if (iph2->status == PHASE2ST_ESTABLISHED) 520 l_ac_errno = EEXIST; 521 else 522 l_ac_errno = 0; 523 break; 524 } 525 526 /* get inbound policy */ 527 memset(&spidx, 0, sizeof(spidx)); 528 spidx.dir = IPSEC_DIR_INBOUND; 529 memcpy(&spidx.src, dst, sizeof(spidx.src)); 530 memcpy(&spidx.dst, src, sizeof(spidx.dst)); 531 spidx.prefs = ndx->prefd; 532 spidx.prefd = ndx->prefs; 533 spidx.ul_proto = ndx->ul_proto; 534 535 sp_in = getsp_r(&spidx); 536 if (sp_in) { 537 plog(LLV_DEBUG, LOCATION, NULL, 538 "suitable inbound SP found: %s.\n", 539 spidx2str(&sp_in->spidx)); 540 } else { 541 l_ac_errno = ENOENT; 542 plog(LLV_NOTIFY, LOCATION, NULL, 543 "no inbound policy found: %s\n", 544 spidx2str(&spidx)); 545 break; 546 } 547 548 /* allocate a phase 2 */ 549 iph2 = newph2(); 550 if (iph2 == NULL) { 551 plog(LLV_ERROR, LOCATION, NULL, 552 "failed to allocate phase2 entry.\n"); 553 break; 554 } 555 iph2->side = INITIATOR; 556 iph2->satype = admin2pfkey_proto(com->ac_proto); 557 iph2->spid = sp_out->id; 558 iph2->seq = pk_getseq(); 559 iph2->status = PHASE2ST_STATUS2; 560 561 /* set end addresses of SA */ 562 iph2->dst = dupsaddr(dst); 563 iph2->src = dupsaddr(src); 564 if (iph2->dst == NULL || iph2->src == NULL) { 565 delph2(iph2); 566 break; 567 } 568 569 if (isakmp_get_sainfo(iph2, sp_out, sp_in) < 0) { 570 delph2(iph2); 571 break; 572 } 573 574 insph2(iph2); 575 if (isakmp_post_acquire(iph2) < 0) { 576 remph2(iph2); 577 delph2(iph2); 578 break; 579 } 580 581 event_list = &iph2->evt_listeners; 582 l_ac_errno = 0; 583 break; 584 } 585 default: 586 /* ignore */ 587 l_ac_errno = ENOTSUP; 588 } 589 break; 590 } 591 592 default: 593 plog(LLV_ERROR, LOCATION, NULL, 594 "invalid command: %d\n", com->ac_cmd); 595 l_ac_errno = ENOTSUP; 596 } 597 598 if ((error = admin_reply(so2, com, l_ac_errno, buf)) != 0) 599 goto out; 600 601 /* start pushing events if so requested */ 602 if ((l_ac_errno == 0) && 603 (com->ac_version >= 1) && 604 (com->ac_cmd == ADMIN_SHOW_EVT || event_list != NULL)) 605 error = evt_subscribe(event_list, so2); 606out: 607 if (buf != NULL) 608 vfree(buf); 609 610 return error; 611} 612 613static int 614admin_reply(so, req, l_ac_errno, buf) 615 int so, l_ac_errno; 616 struct admin_com *req; 617 vchar_t *buf; 618{ 619 int tlen; 620 struct admin_com *combuf; 621 char *retbuf = NULL; 622 623 if (buf != NULL) 624 tlen = sizeof(*combuf) + buf->l; 625 else 626 tlen = sizeof(*combuf); 627 628 retbuf = racoon_calloc(1, tlen); 629 if (retbuf == NULL) { 630 plog(LLV_ERROR, LOCATION, NULL, 631 "failed to allocate admin buffer\n"); 632 return -1; 633 } 634 635 combuf = (struct admin_com *) retbuf; 636 combuf->ac_len = tlen; 637 combuf->ac_cmd = req->ac_cmd & ~ADMIN_FLAG_VERSION; 638 combuf->ac_errno = l_ac_errno; 639 combuf->ac_proto = req->ac_proto; 640 641 if (buf != NULL) 642 memcpy(retbuf + sizeof(*combuf), buf->v, buf->l); 643 644 tlen = send(so, retbuf, tlen, 0); 645 racoon_free(retbuf); 646 if (tlen < 0) { 647 plog(LLV_ERROR, LOCATION, NULL, 648 "failed to send admin command: %s\n", 649 strerror(errno)); 650 return -1; 651 } 652 653 return 0; 654} 655 656/* ADMIN_PROTO -> SADB_SATYPE */ 657int 658admin2pfkey_proto(proto) 659 u_int proto; 660{ 661 switch (proto) { 662 case ADMIN_PROTO_IPSEC: 663 return SADB_SATYPE_UNSPEC; 664 case ADMIN_PROTO_AH: 665 return SADB_SATYPE_AH; 666 case ADMIN_PROTO_ESP: 667 return SADB_SATYPE_ESP; 668 default: 669 plog(LLV_ERROR, LOCATION, NULL, 670 "unsupported proto for admin: %d\n", proto); 671 return -1; 672 } 673 /*NOTREACHED*/ 674} 675 676int 677admin_init() 678{ 679 if (adminsock_path == NULL) { 680 lcconf->sock_admin = -1; 681 return 0; 682 } 683 684 memset(&sunaddr, 0, sizeof(sunaddr)); 685 sunaddr.sun_family = AF_UNIX; 686 snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), 687 "%s", adminsock_path); 688 689 lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0); 690 if (lcconf->sock_admin == -1) { 691 plog(LLV_ERROR, LOCATION, NULL, 692 "socket: %s\n", strerror(errno)); 693 return -1; 694 } 695 close_on_exec(lcconf->sock_admin); 696 697 unlink(sunaddr.sun_path); 698 if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr, 699 sizeof(sunaddr)) != 0) { 700 plog(LLV_ERROR, LOCATION, NULL, 701 "bind(sockname:%s): %s\n", 702 sunaddr.sun_path, strerror(errno)); 703 (void)close(lcconf->sock_admin); 704 return -1; 705 } 706 707 if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) { 708 plog(LLV_ERROR, LOCATION, NULL, 709 "chown(%s, %d, %d): %s\n", 710 sunaddr.sun_path, adminsock_owner, 711 adminsock_group, strerror(errno)); 712 (void)close(lcconf->sock_admin); 713 return -1; 714 } 715 716 if (chmod(sunaddr.sun_path, adminsock_mode) != 0) { 717 plog(LLV_ERROR, LOCATION, NULL, 718 "chmod(%s, 0%03o): %s\n", 719 sunaddr.sun_path, adminsock_mode, strerror(errno)); 720 (void)close(lcconf->sock_admin); 721 return -1; 722 } 723 724 if (listen(lcconf->sock_admin, 5) != 0) { 725 plog(LLV_ERROR, LOCATION, NULL, 726 "listen(sockname:%s): %s\n", 727 sunaddr.sun_path, strerror(errno)); 728 (void)close(lcconf->sock_admin); 729 return -1; 730 } 731 732 monitor_fd(lcconf->sock_admin, admin_handler, NULL); 733 plog(LLV_DEBUG, LOCATION, NULL, 734 "open %s as racoon management.\n", sunaddr.sun_path); 735 736 return 0; 737} 738 739int 740admin_close() 741{ 742 unmonitor_fd(lcconf->sock_admin); 743 close(lcconf->sock_admin); 744 return 0; 745} 746 747#endif 748