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