admin.c revision 1.30
1/* $NetBSD: admin.c,v 1.30 2009/04/20 13:22:00 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[LOGINLEN+1]; 329 int found = 0, len = com->ac_len - sizeof(com); 330 331 if (len > LOGINLEN) { 332 plog(LLV_ERROR, LOCATION, NULL, 333 "malformed message (login too long)\n"); 334 break; 335 } 336 337 memcpy(user, (char *)(com + 1), len); 338 user[len] = 0; 339 340 found = purgeph1bylogin(user); 341 plog(LLV_INFO, LOCATION, NULL, 342 "deleted %d SA for user \"%s\"\n", found, user); 343 344 break; 345 } 346#endif 347 348 case ADMIN_DELETE_ALL_SA_DST: { 349 struct ph1handle *iph1; 350 struct sockaddr *dst; 351 char *loc, *rem; 352 353 dst = (struct sockaddr *) 354 &((struct admin_com_indexes *) 355 ((caddr_t)com + sizeof(*com)))->dst; 356 357 rem = racoon_strdup(saddrwop2str(dst)); 358 STRDUP_FATAL(rem); 359 360 plog(LLV_INFO, LOCATION, NULL, 361 "Flushing all SAs for peer %s\n", rem); 362 363 while ((iph1 = getph1bydstaddrwop(dst)) != NULL) { 364 loc = racoon_strdup(saddrwop2str(iph1->local)); 365 STRDUP_FATAL(loc); 366 367 if (iph1->status >= PHASE1ST_ESTABLISHED) 368 isakmp_info_send_d1(iph1); 369 purge_remote(iph1); 370 371 racoon_free(loc); 372 } 373 374 racoon_free(rem); 375 break; 376 } 377 378 case ADMIN_ESTABLISH_SA_PSK: { 379 struct admin_com_psk *acp; 380 char *data; 381 382 acp = (struct admin_com_psk *) 383 ((char *)com + sizeof(*com) + 384 sizeof(struct admin_com_indexes)); 385 386 idtype = acp->id_type; 387 388 if ((id = vmalloc(acp->id_len)) == NULL) { 389 plog(LLV_ERROR, LOCATION, NULL, 390 "cannot allocate memory: %s\n", 391 strerror(errno)); 392 break; 393 } 394 data = (char *)(acp + 1); 395 memcpy(id->v, data, id->l); 396 397 if ((key = vmalloc(acp->key_len)) == NULL) { 398 plog(LLV_ERROR, LOCATION, NULL, 399 "cannot allocate memory: %s\n", 400 strerror(errno)); 401 vfree(id); 402 id = NULL; 403 break; 404 } 405 data = (char *)(data + acp->id_len); 406 memcpy(key->v, data, key->l); 407 } 408 /* FALLTHROUGH */ 409 case ADMIN_ESTABLISH_SA: { 410 struct admin_com_indexes *ndx; 411 struct sockaddr *dst; 412 struct sockaddr *src; 413 char *name = NULL; 414 415 ndx = (struct admin_com_indexes *) ((caddr_t)com + sizeof(*com)); 416 src = (struct sockaddr *) &ndx->src; 417 dst = (struct sockaddr *) &ndx->dst; 418 419 if (com->ac_cmd == ADMIN_ESTABLISH_SA && 420 com->ac_len > sizeof(*com) + sizeof(*ndx)) 421 name = (char *) ((caddr_t) ndx + sizeof(*ndx)); 422 423 switch (com->ac_proto) { 424 case ADMIN_PROTO_ISAKMP: { 425 struct ph1handle *ph1; 426 struct remoteconf *rmconf; 427 u_int16_t port; 428 429 l_ac_errno = -1; 430 431 /* connected already? */ 432 ph1 = getph1byaddrwop(src, dst); 433 if (ph1 != NULL) { 434 event_list = &ph1->evt_listeners; 435 if (ph1->status == PHASE1ST_ESTABLISHED) 436 l_ac_errno = EEXIST; 437 else 438 l_ac_errno = 0; 439 break; 440 } 441 442 /* search appropreate configuration */ 443 if (name == NULL) 444 rmconf = getrmconf(dst, 0); 445 else 446 rmconf = getrmconf_by_name(name); 447 if (rmconf == NULL) { 448 plog(LLV_ERROR, LOCATION, NULL, 449 "no configuration found " 450 "for %s\n", saddrwop2str(dst)); 451 break; 452 } 453 454#ifdef ENABLE_HYBRID 455 /* XXX This overwrites rmconf information globally. */ 456 /* Set the id and key */ 457 if (id && key) { 458 if (xauth_rmconf_used(&rmconf->xauth) == -1) 459 break; 460 461 if (rmconf->xauth->login != NULL) { 462 vfree(rmconf->xauth->login); 463 rmconf->xauth->login = NULL; 464 } 465 if (rmconf->xauth->pass != NULL) { 466 vfree(rmconf->xauth->pass); 467 rmconf->xauth->pass = NULL; 468 } 469 470 rmconf->xauth->login = id; 471 rmconf->xauth->pass = key; 472 } 473#endif 474 475 plog(LLV_INFO, LOCATION, NULL, 476 "accept a request to establish IKE-SA: " 477 "%s\n", saddrwop2str(dst)); 478 479 /* begin ident mode */ 480 ph1 = isakmp_ph1begin_i(rmconf, dst, src); 481 if (ph1 == NULL) 482 break; 483 484 event_list = &ph1->evt_listeners; 485 l_ac_errno = 0; 486 break; 487 } 488 case ADMIN_PROTO_AH: 489 case ADMIN_PROTO_ESP: { 490 struct ph2handle *iph2; 491 struct secpolicy *sp_out = NULL, *sp_in = NULL; 492 struct policyindex spidx; 493 494 l_ac_errno = -1; 495 496 /* got outbound policy */ 497 memset(&spidx, 0, sizeof(spidx)); 498 spidx.dir = IPSEC_DIR_OUTBOUND; 499 memcpy(&spidx.src, src, sizeof(spidx.src)); 500 memcpy(&spidx.dst, dst, sizeof(spidx.dst)); 501 spidx.prefs = ndx->prefs; 502 spidx.prefd = ndx->prefd; 503 spidx.ul_proto = ndx->ul_proto; 504 505 sp_out = getsp_r(&spidx); 506 if (sp_out) { 507 plog(LLV_DEBUG, LOCATION, NULL, 508 "suitable outbound SP found: %s.\n", 509 spidx2str(&sp_out->spidx)); 510 } else { 511 l_ac_errno = ENOENT; 512 plog(LLV_NOTIFY, LOCATION, NULL, 513 "no outbound policy found: %s\n", 514 spidx2str(&spidx)); 515 break; 516 } 517 518 iph2 = getph2byid(src, dst, sp_out->id); 519 if (iph2 != NULL) { 520 event_list = &iph2->evt_listeners; 521 if (iph2->status == PHASE2ST_ESTABLISHED) 522 l_ac_errno = EEXIST; 523 else 524 l_ac_errno = 0; 525 break; 526 } 527 528 /* get inbound policy */ 529 memset(&spidx, 0, sizeof(spidx)); 530 spidx.dir = IPSEC_DIR_INBOUND; 531 memcpy(&spidx.src, dst, sizeof(spidx.src)); 532 memcpy(&spidx.dst, src, sizeof(spidx.dst)); 533 spidx.prefs = ndx->prefd; 534 spidx.prefd = ndx->prefs; 535 spidx.ul_proto = ndx->ul_proto; 536 537 sp_in = getsp_r(&spidx); 538 if (sp_in) { 539 plog(LLV_DEBUG, LOCATION, NULL, 540 "suitable inbound SP found: %s.\n", 541 spidx2str(&sp_in->spidx)); 542 } else { 543 l_ac_errno = ENOENT; 544 plog(LLV_NOTIFY, LOCATION, NULL, 545 "no inbound policy found: %s\n", 546 spidx2str(&spidx)); 547 break; 548 } 549 550 /* allocate a phase 2 */ 551 iph2 = newph2(); 552 if (iph2 == NULL) { 553 plog(LLV_ERROR, LOCATION, NULL, 554 "failed to allocate phase2 entry.\n"); 555 break; 556 } 557 iph2->side = INITIATOR; 558 iph2->satype = admin2pfkey_proto(com->ac_proto); 559 iph2->spid = sp_out->id; 560 iph2->seq = pk_getseq(); 561 iph2->status = PHASE2ST_STATUS2; 562 563 /* set end addresses of SA */ 564 iph2->dst = dupsaddr(dst); 565 iph2->src = dupsaddr(src); 566 if (iph2->dst == NULL || iph2->src == NULL) { 567 delph2(iph2); 568 break; 569 } 570 571 if (isakmp_get_sainfo(iph2, sp_out, sp_in) < 0) { 572 delph2(iph2); 573 break; 574 } 575 576 insph2(iph2); 577 if (isakmp_post_acquire(iph2) < 0) { 578 remph2(iph2); 579 delph2(iph2); 580 break; 581 } 582 583 event_list = &iph2->evt_listeners; 584 l_ac_errno = 0; 585 break; 586 } 587 default: 588 /* ignore */ 589 l_ac_errno = ENOTSUP; 590 } 591 break; 592 } 593 594 default: 595 plog(LLV_ERROR, LOCATION, NULL, 596 "invalid command: %d\n", com->ac_cmd); 597 l_ac_errno = ENOTSUP; 598 } 599 600 if ((error = admin_reply(so2, com, l_ac_errno, buf)) != 0) 601 goto out; 602 603 /* start pushing events if so requested */ 604 if ((l_ac_errno == 0) && 605 (com->ac_version >= 1) && 606 (com->ac_cmd == ADMIN_SHOW_EVT || event_list != NULL)) 607 error = evt_subscribe(event_list, so2); 608out: 609 if (buf != NULL) 610 vfree(buf); 611 612 return error; 613} 614 615static int 616admin_reply(so, req, l_ac_errno, buf) 617 int so, l_ac_errno; 618 struct admin_com *req; 619 vchar_t *buf; 620{ 621 int tlen; 622 struct admin_com *combuf; 623 char *retbuf = NULL; 624 625 if (buf != NULL) 626 tlen = sizeof(*combuf) + buf->l; 627 else 628 tlen = sizeof(*combuf); 629 630 retbuf = racoon_calloc(1, tlen); 631 if (retbuf == NULL) { 632 plog(LLV_ERROR, LOCATION, NULL, 633 "failed to allocate admin buffer\n"); 634 return -1; 635 } 636 637 combuf = (struct admin_com *) retbuf; 638 combuf->ac_len = tlen; 639 combuf->ac_cmd = req->ac_cmd & ~ADMIN_FLAG_VERSION; 640 combuf->ac_errno = l_ac_errno; 641 combuf->ac_proto = req->ac_proto; 642 643 if (buf != NULL) 644 memcpy(retbuf + sizeof(*combuf), buf->v, buf->l); 645 646 tlen = send(so, retbuf, tlen, 0); 647 racoon_free(retbuf); 648 if (tlen < 0) { 649 plog(LLV_ERROR, LOCATION, NULL, 650 "failed to send admin command: %s\n", 651 strerror(errno)); 652 return -1; 653 } 654 655 return 0; 656} 657 658/* ADMIN_PROTO -> SADB_SATYPE */ 659int 660admin2pfkey_proto(proto) 661 u_int proto; 662{ 663 switch (proto) { 664 case ADMIN_PROTO_IPSEC: 665 return SADB_SATYPE_UNSPEC; 666 case ADMIN_PROTO_AH: 667 return SADB_SATYPE_AH; 668 case ADMIN_PROTO_ESP: 669 return SADB_SATYPE_ESP; 670 default: 671 plog(LLV_ERROR, LOCATION, NULL, 672 "unsupported proto for admin: %d\n", proto); 673 return -1; 674 } 675 /*NOTREACHED*/ 676} 677 678int 679admin_init() 680{ 681 if (adminsock_path == NULL) { 682 lcconf->sock_admin = -1; 683 return 0; 684 } 685 686 memset(&sunaddr, 0, sizeof(sunaddr)); 687 sunaddr.sun_family = AF_UNIX; 688 snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), 689 "%s", adminsock_path); 690 691 lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0); 692 if (lcconf->sock_admin == -1) { 693 plog(LLV_ERROR, LOCATION, NULL, 694 "socket: %s\n", strerror(errno)); 695 return -1; 696 } 697 close_on_exec(lcconf->sock_admin); 698 699 unlink(sunaddr.sun_path); 700 if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr, 701 sizeof(sunaddr)) != 0) { 702 plog(LLV_ERROR, LOCATION, NULL, 703 "bind(sockname:%s): %s\n", 704 sunaddr.sun_path, strerror(errno)); 705 (void)close(lcconf->sock_admin); 706 return -1; 707 } 708 709 if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) { 710 plog(LLV_ERROR, LOCATION, NULL, 711 "chown(%s, %d, %d): %s\n", 712 sunaddr.sun_path, adminsock_owner, 713 adminsock_group, strerror(errno)); 714 (void)close(lcconf->sock_admin); 715 return -1; 716 } 717 718 if (chmod(sunaddr.sun_path, adminsock_mode) != 0) { 719 plog(LLV_ERROR, LOCATION, NULL, 720 "chmod(%s, 0%03o): %s\n", 721 sunaddr.sun_path, adminsock_mode, strerror(errno)); 722 (void)close(lcconf->sock_admin); 723 return -1; 724 } 725 726 if (listen(lcconf->sock_admin, 5) != 0) { 727 plog(LLV_ERROR, LOCATION, NULL, 728 "listen(sockname:%s): %s\n", 729 sunaddr.sun_path, strerror(errno)); 730 (void)close(lcconf->sock_admin); 731 return -1; 732 } 733 734 monitor_fd(lcconf->sock_admin, admin_handler, NULL); 735 plog(LLV_DEBUG, LOCATION, NULL, 736 "open %s as racoon management.\n", sunaddr.sun_path); 737 738 return 0; 739} 740 741int 742admin_close() 743{ 744 unmonitor_fd(lcconf->sock_admin); 745 close(lcconf->sock_admin); 746 return 0; 747} 748 749#endif 750