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