admin.c revision 1.25
1/* $NetBSD: admin.c,v 1.25 2008/08/29 00:30:15 gmcgarry 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 99int 100admin_handler() 101{ 102 int so2; 103 struct sockaddr_storage from; 104 socklen_t fromlen = sizeof(from); 105 struct admin_com com; 106 char *combuf = NULL; 107 int len, error = -1; 108 109 so2 = accept(lcconf->sock_admin, (struct sockaddr *)&from, &fromlen); 110 if (so2 < 0) { 111 plog(LLV_ERROR, LOCATION, NULL, 112 "failed to accept admin command: %s\n", 113 strerror(errno)); 114 return -1; 115 } 116 close_on_exec(so2); 117 118 /* get buffer length */ 119 while ((len = recv(so2, (char *)&com, sizeof(com), MSG_PEEK)) < 0) { 120 if (errno == EINTR) 121 continue; 122 plog(LLV_ERROR, LOCATION, NULL, 123 "failed to recv admin command: %s\n", 124 strerror(errno)); 125 goto end; 126 } 127 128 /* sanity check */ 129 if (len < sizeof(com)) { 130 plog(LLV_ERROR, LOCATION, NULL, 131 "invalid header length of admin command\n"); 132 goto end; 133 } 134 135 /* get buffer to receive */ 136 if ((combuf = racoon_malloc(com.ac_len)) == 0) { 137 plog(LLV_ERROR, LOCATION, NULL, 138 "failed to alloc buffer for admin command\n"); 139 goto end; 140 } 141 142 /* get real data */ 143 while ((len = recv(so2, combuf, com.ac_len, 0)) < 0) { 144 if (errno == EINTR) 145 continue; 146 plog(LLV_ERROR, LOCATION, NULL, 147 "failed to recv admin command: %s\n", 148 strerror(errno)); 149 goto end; 150 } 151 152 error = admin_process(so2, combuf); 153 154end: 155 if (error == -2) { 156 plog(LLV_DEBUG, LOCATION, NULL, 157 "[%d] admin connection established\n", so2); 158 } else { 159 (void)close(so2); 160 } 161 162 if (combuf) 163 racoon_free(combuf); 164 165 return error; 166} 167 168/* 169 * main child's process. 170 */ 171static int 172admin_process(so2, combuf) 173 int so2; 174 char *combuf; 175{ 176 struct admin_com *com = (struct admin_com *)combuf; 177 vchar_t *buf = NULL; 178 vchar_t *id = NULL; 179 vchar_t *key = NULL; 180 int idtype = 0; 181 int error = 0, l_ac_errno = 0; 182 struct evt_listener_list *event_list = NULL; 183 184 if (com->ac_cmd & ADMIN_FLAG_VERSION) 185 com->ac_cmd &= ~ADMIN_FLAG_VERSION; 186 else 187 com->ac_version = 0; 188 189 switch (com->ac_cmd) { 190 case ADMIN_RELOAD_CONF: 191 signal_handler(SIGHUP); 192 break; 193 194 case ADMIN_SHOW_SCHED: { 195 caddr_t p = NULL; 196 int len; 197 198 if (sched_dump(&p, &len) != -1) { 199 buf = vmalloc(len); 200 if (buf != NULL) 201 memcpy(buf->v, p, len); 202 else 203 l_ac_errno = ENOMEM; 204 racoon_free(p); 205 } else 206 l_ac_errno = ENOMEM; 207 break; 208 } 209 210 case ADMIN_SHOW_EVT: 211 if (com->ac_version == 0) { 212 buf = evt_dump(); 213 l_ac_errno = 0; 214 } 215 break; 216 217 case ADMIN_SHOW_SA: 218 switch (com->ac_proto) { 219 case ADMIN_PROTO_ISAKMP: 220 buf = dumpph1(); 221 if (buf == NULL) 222 l_ac_errno = ENOMEM; 223 break; 224 case ADMIN_PROTO_IPSEC: 225 case ADMIN_PROTO_AH: 226 case ADMIN_PROTO_ESP: { 227 u_int p; 228 p = admin2pfkey_proto(com->ac_proto); 229 if (p != -1) { 230 buf = pfkey_dump_sadb(p); 231 if (buf == NULL) 232 l_ac_errno = ENOMEM; 233 } else 234 l_ac_errno = EINVAL; 235 break; 236 } 237 case ADMIN_PROTO_INTERNAL: 238 default: 239 l_ac_errno = ENOTSUP; 240 break; 241 } 242 break; 243 244 case ADMIN_GET_SA_CERT: { 245 struct admin_com_indexes *ndx; 246 struct sockaddr *src, *dst; 247 struct ph1handle *iph1; 248 249 ndx = (struct admin_com_indexes *) ((caddr_t)com + sizeof(*com)); 250 src = (struct sockaddr *) &ndx->src; 251 dst = (struct sockaddr *) &ndx->dst; 252 253 if (com->ac_proto != ADMIN_PROTO_ISAKMP) { 254 l_ac_errno = ENOTSUP; 255 break; 256 } 257 258 iph1 = getph1byaddrwop(src, dst); 259 if (iph1 == NULL) { 260 l_ac_errno = ENOENT; 261 break; 262 } 263 264 if (iph1->cert_p != NULL) 265 buf = vdup(&iph1->cert_p->cert); 266 break; 267 } 268 269 case ADMIN_FLUSH_SA: 270 switch (com->ac_proto) { 271 case ADMIN_PROTO_ISAKMP: 272 flushph1(); 273 break; 274 case ADMIN_PROTO_IPSEC: 275 case ADMIN_PROTO_AH: 276 case ADMIN_PROTO_ESP: 277 pfkey_flush_sadb(com->ac_proto); 278 break; 279 case ADMIN_PROTO_INTERNAL: 280 /*XXX flushph2();*/ 281 default: 282 l_ac_errno = ENOTSUP; 283 break; 284 } 285 break; 286 287 case ADMIN_DELETE_SA: { 288 struct ph1handle *iph1; 289 struct sockaddr *dst; 290 struct sockaddr *src; 291 char *loc, *rem; 292 293 src = (struct sockaddr *) 294 &((struct admin_com_indexes *) 295 ((caddr_t)com + sizeof(*com)))->src; 296 dst = (struct sockaddr *) 297 &((struct admin_com_indexes *) 298 ((caddr_t)com + sizeof(*com)))->dst; 299 300 loc = racoon_strdup(saddrwop2str(src)); 301 rem = racoon_strdup(saddrwop2str(dst)); 302 STRDUP_FATAL(loc); 303 STRDUP_FATAL(rem); 304 305 if ((iph1 = getph1byaddrwop(src, dst)) == NULL) { 306 plog(LLV_ERROR, LOCATION, NULL, 307 "phase 1 for %s -> %s not found\n", loc, rem); 308 } else { 309 if (iph1->status == PHASE1ST_ESTABLISHED) 310 isakmp_info_send_d1(iph1); 311 purge_remote(iph1); 312 } 313 314 racoon_free(loc); 315 racoon_free(rem); 316 break; 317 } 318 319#ifdef ENABLE_HYBRID 320 case ADMIN_LOGOUT_USER: { 321 struct ph1handle *iph1; 322 char *user; 323 int found = 0; 324 325 if (com->ac_len > sizeof(com) + LOGINLEN + 1) { 326 plog(LLV_ERROR, LOCATION, NULL, 327 "malformed message (login too long)\n"); 328 break; 329 } 330 331 user = (char *)(com + 1); 332 found = purgeph1bylogin(user); 333 plog(LLV_INFO, LOCATION, NULL, 334 "deleted %d SA for user \"%s\"\n", found, user); 335 336 break; 337 } 338#endif 339 340 case ADMIN_DELETE_ALL_SA_DST: { 341 struct ph1handle *iph1; 342 struct sockaddr *dst; 343 char *loc, *rem; 344 345 dst = (struct sockaddr *) 346 &((struct admin_com_indexes *) 347 ((caddr_t)com + sizeof(*com)))->dst; 348 349 rem = racoon_strdup(saddrwop2str(dst)); 350 STRDUP_FATAL(rem); 351 352 plog(LLV_INFO, LOCATION, NULL, 353 "Flushing all SAs for peer %s\n", rem); 354 355 while ((iph1 = getph1bydstaddrwop(dst)) != NULL) { 356 loc = racoon_strdup(saddrwop2str(iph1->local)); 357 STRDUP_FATAL(loc); 358 359 if (iph1->status == PHASE1ST_ESTABLISHED) 360 isakmp_info_send_d1(iph1); 361 purge_remote(iph1); 362 363 racoon_free(loc); 364 } 365 366 racoon_free(rem); 367 break; 368 } 369 370 case ADMIN_ESTABLISH_SA_PSK: { 371 struct admin_com_psk *acp; 372 char *data; 373 374 acp = (struct admin_com_psk *) 375 ((char *)com + sizeof(*com) + 376 sizeof(struct admin_com_indexes)); 377 378 idtype = acp->id_type; 379 380 if ((id = vmalloc(acp->id_len)) == NULL) { 381 plog(LLV_ERROR, LOCATION, NULL, 382 "cannot allocate memory: %s\n", 383 strerror(errno)); 384 break; 385 } 386 data = (char *)(acp + 1); 387 memcpy(id->v, data, id->l); 388 389 if ((key = vmalloc(acp->key_len)) == NULL) { 390 plog(LLV_ERROR, LOCATION, NULL, 391 "cannot allocate memory: %s\n", 392 strerror(errno)); 393 vfree(id); 394 id = NULL; 395 break; 396 } 397 data = (char *)(data + acp->id_len); 398 memcpy(key->v, data, key->l); 399 } 400 /* FALLTHROUGH */ 401 case ADMIN_ESTABLISH_SA: { 402 struct admin_com_indexes *ndx; 403 struct sockaddr *dst; 404 struct sockaddr *src; 405 406 ndx = (struct admin_com_indexes *) ((caddr_t)com + sizeof(*com)); 407 src = (struct sockaddr *) &ndx->src; 408 dst = (struct sockaddr *) &ndx->dst; 409 410 switch (com->ac_proto) { 411 case ADMIN_PROTO_ISAKMP: { 412 struct ph1handle *ph1; 413 struct remoteconf *rmconf; 414 struct sockaddr *remote = NULL; 415 struct sockaddr *local = NULL; 416 u_int16_t port; 417 418 l_ac_errno = -1; 419 420 /* connected already? */ 421 ph1 = getph1byaddrwop(src, dst); 422 if (ph1 != NULL) { 423 event_list = &ph1->evt_listeners; 424 if (ph1->status == PHASE1ST_ESTABLISHED) 425 l_ac_errno = EEXIST; 426 else 427 l_ac_errno = 0; 428 break; 429 } 430 431 /* search appropreate configuration */ 432 rmconf = getrmconf(dst); 433 if (rmconf == NULL) { 434 plog(LLV_ERROR, LOCATION, NULL, 435 "no configuration found " 436 "for %s\n", saddrwop2str(dst)); 437 goto out1; 438 } 439 440 /* get remote IP address and port number. */ 441 if ((remote = dupsaddr(dst)) == NULL) 442 goto out1; 443 444 port = extract_port(rmconf->remote); 445 if (set_port(remote, port) == NULL) 446 goto out1; 447 448 /* get local address */ 449 if ((local = dupsaddr(src)) == NULL) 450 goto out1; 451 452 port = getmyaddrsport(local); 453 if (set_port(local, port) == NULL) 454 goto out1; 455 456#ifdef ENABLE_HYBRID 457 /* Set the id and key */ 458 if (id && key) { 459 if (xauth_rmconf_used(&rmconf->xauth) == -1) 460 goto out1; 461 462 if (rmconf->xauth->login != NULL) { 463 vfree(rmconf->xauth->login); 464 rmconf->xauth->login = NULL; 465 } 466 if (rmconf->xauth->pass != NULL) { 467 vfree(rmconf->xauth->pass); 468 rmconf->xauth->pass = NULL; 469 } 470 471 rmconf->xauth->login = id; 472 rmconf->xauth->pass = key; 473 } 474#endif 475 476 plog(LLV_INFO, LOCATION, NULL, 477 "accept a request to establish IKE-SA: " 478 "%s\n", saddrwop2str(remote)); 479 480 /* begin ident mode */ 481 ph1 = isakmp_ph1begin_i(rmconf, remote, local); 482 if (ph1 == NULL) 483 goto out1; 484 485 event_list = &ph1->evt_listeners; 486 l_ac_errno = 0; 487out1: 488 if (local != NULL) 489 racoon_free(local); 490 if (remote != NULL) 491 racoon_free(remote); 492 break; 493 } 494 case ADMIN_PROTO_AH: 495 case ADMIN_PROTO_ESP: { 496 struct ph2handle *iph2; 497 struct secpolicy *sp_out = NULL, *sp_in = NULL; 498 struct policyindex spidx; 499 500 l_ac_errno = -1; 501 502 /* got outbound policy */ 503 memset(&spidx, 0, sizeof(spidx)); 504 spidx.dir = IPSEC_DIR_OUTBOUND; 505 memcpy(&spidx.src, src, sizeof(spidx.src)); 506 memcpy(&spidx.dst, dst, sizeof(spidx.dst)); 507 spidx.prefs = ndx->prefs; 508 spidx.prefd = ndx->prefd; 509 spidx.ul_proto = ndx->ul_proto; 510 511 sp_out = getsp_r(&spidx); 512 if (sp_out) { 513 plog(LLV_DEBUG, LOCATION, NULL, 514 "suitable outbound SP found: %s.\n", 515 spidx2str(&sp_out->spidx)); 516 } else { 517 l_ac_errno = ENOENT; 518 plog(LLV_NOTIFY, LOCATION, NULL, 519 "no outbound policy found: %s\n", 520 spidx2str(&spidx)); 521 break; 522 } 523 524 iph2 = getph2byid(src, dst, sp_out->id); 525 if (iph2 != NULL) { 526 event_list = &iph2->evt_listeners; 527 if (iph2->status == PHASE2ST_ESTABLISHED) 528 l_ac_errno = EEXIST; 529 else 530 l_ac_errno = 0; 531 break; 532 } 533 534 /* get inbound policy */ 535 memset(&spidx, 0, sizeof(spidx)); 536 spidx.dir = IPSEC_DIR_INBOUND; 537 memcpy(&spidx.src, dst, sizeof(spidx.src)); 538 memcpy(&spidx.dst, src, sizeof(spidx.dst)); 539 spidx.prefs = ndx->prefd; 540 spidx.prefd = ndx->prefs; 541 spidx.ul_proto = ndx->ul_proto; 542 543 sp_in = getsp_r(&spidx); 544 if (sp_in) { 545 plog(LLV_DEBUG, LOCATION, NULL, 546 "suitable inbound SP found: %s.\n", 547 spidx2str(&sp_in->spidx)); 548 } else { 549 l_ac_errno = ENOENT; 550 plog(LLV_NOTIFY, LOCATION, NULL, 551 "no inbound policy found: %s\n", 552 spidx2str(&spidx)); 553 break; 554 } 555 556 /* allocate a phase 2 */ 557 iph2 = newph2(); 558 if (iph2 == NULL) { 559 plog(LLV_ERROR, LOCATION, NULL, 560 "failed to allocate phase2 entry.\n"); 561 break; 562 } 563 iph2->side = INITIATOR; 564 iph2->satype = admin2pfkey_proto(com->ac_proto); 565 iph2->spid = sp_out->id; 566 iph2->seq = pk_getseq(); 567 iph2->status = PHASE2ST_STATUS2; 568 569 /* set end addresses of SA */ 570 iph2->dst = dupsaddr(dst); 571 iph2->src = dupsaddr(src); 572 if (iph2->dst == NULL || iph2->src == NULL) { 573 delph2(iph2); 574 break; 575 } 576 577 if (isakmp_get_sainfo(iph2, sp_out, sp_in) < 0) { 578 delph2(iph2); 579 break; 580 } 581 582 insph2(iph2); 583 if (isakmp_post_acquire(iph2) < 0) { 584 unbindph12(iph2); 585 remph2(iph2); 586 delph2(iph2); 587 break; 588 } 589 590 event_list = &iph2->evt_listeners; 591 l_ac_errno = 0; 592 break; 593 } 594 default: 595 /* ignore */ 596 l_ac_errno = ENOTSUP; 597 } 598 break; 599 } 600 601 default: 602 plog(LLV_ERROR, LOCATION, NULL, 603 "invalid command: %d\n", com->ac_cmd); 604 l_ac_errno = ENOTSUP; 605 } 606 607 if ((error = admin_reply(so2, com, l_ac_errno, buf)) != 0) 608 goto out; 609 610 /* start pushing events if so requested */ 611 if ((l_ac_errno == 0) && 612 (com->ac_version >= 1) && 613 (com->ac_cmd == ADMIN_SHOW_EVT || event_list != NULL)) 614 error = evt_subscribe(event_list, so2); 615out: 616 if (buf != NULL) 617 vfree(buf); 618 619 return error; 620} 621 622static int 623admin_reply(so, req, l_ac_errno, buf) 624 int so, l_ac_errno; 625 struct admin_com *req; 626 vchar_t *buf; 627{ 628 int tlen; 629 struct admin_com *combuf; 630 char *retbuf = NULL; 631 632 if (buf != NULL) 633 tlen = sizeof(*combuf) + buf->l; 634 else 635 tlen = sizeof(*combuf); 636 637 retbuf = racoon_calloc(1, tlen); 638 if (retbuf == NULL) { 639 plog(LLV_ERROR, LOCATION, NULL, 640 "failed to allocate admin buffer\n"); 641 return -1; 642 } 643 644 combuf = (struct admin_com *) retbuf; 645 combuf->ac_len = tlen; 646 combuf->ac_cmd = req->ac_cmd & ~ADMIN_FLAG_VERSION; 647 combuf->ac_errno = l_ac_errno; 648 combuf->ac_proto = req->ac_proto; 649 650 if (buf != NULL) 651 memcpy(retbuf + sizeof(*combuf), buf->v, buf->l); 652 653 tlen = send(so, retbuf, tlen, 0); 654 racoon_free(retbuf); 655 if (tlen < 0) { 656 plog(LLV_ERROR, LOCATION, NULL, 657 "failed to send admin command: %s\n", 658 strerror(errno)); 659 return -1; 660 } 661 662 return 0; 663} 664 665/* ADMIN_PROTO -> SADB_SATYPE */ 666int 667admin2pfkey_proto(proto) 668 u_int proto; 669{ 670 switch (proto) { 671 case ADMIN_PROTO_IPSEC: 672 return SADB_SATYPE_UNSPEC; 673 case ADMIN_PROTO_AH: 674 return SADB_SATYPE_AH; 675 case ADMIN_PROTO_ESP: 676 return SADB_SATYPE_ESP; 677 default: 678 plog(LLV_ERROR, LOCATION, NULL, 679 "unsupported proto for admin: %d\n", proto); 680 return -1; 681 } 682 /*NOTREACHED*/ 683} 684 685int 686admin_init() 687{ 688 if (adminsock_path == NULL) { 689 lcconf->sock_admin = -1; 690 return 0; 691 } 692 693 memset(&sunaddr, 0, sizeof(sunaddr)); 694 sunaddr.sun_family = AF_UNIX; 695 snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), 696 "%s", adminsock_path); 697 698 lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0); 699 if (lcconf->sock_admin == -1) { 700 plog(LLV_ERROR, LOCATION, NULL, 701 "socket: %s\n", strerror(errno)); 702 return -1; 703 } 704 close_on_exec(lcconf->sock_admin); 705 706 unlink(sunaddr.sun_path); 707 if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr, 708 sizeof(sunaddr)) != 0) { 709 plog(LLV_ERROR, LOCATION, NULL, 710 "bind(sockname:%s): %s\n", 711 sunaddr.sun_path, strerror(errno)); 712 (void)close(lcconf->sock_admin); 713 return -1; 714 } 715 716 if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) { 717 plog(LLV_ERROR, LOCATION, NULL, 718 "chown(%s, %d, %d): %s\n", 719 sunaddr.sun_path, adminsock_owner, 720 adminsock_group, strerror(errno)); 721 (void)close(lcconf->sock_admin); 722 return -1; 723 } 724 725 if (chmod(sunaddr.sun_path, adminsock_mode) != 0) { 726 plog(LLV_ERROR, LOCATION, NULL, 727 "chmod(%s, 0%03o): %s\n", 728 sunaddr.sun_path, adminsock_mode, strerror(errno)); 729 (void)close(lcconf->sock_admin); 730 return -1; 731 } 732 733 if (listen(lcconf->sock_admin, 5) != 0) { 734 plog(LLV_ERROR, LOCATION, NULL, 735 "listen(sockname:%s): %s\n", 736 sunaddr.sun_path, strerror(errno)); 737 (void)close(lcconf->sock_admin); 738 return -1; 739 } 740 plog(LLV_DEBUG, LOCATION, NULL, 741 "open %s as racoon management.\n", sunaddr.sun_path); 742 743 return 0; 744} 745 746int 747admin_close() 748{ 749 close(lcconf->sock_admin); 750 return 0; 751} 752#endif 753 754