admin.c revision 1.19
1/* $NetBSD: admin.c,v 1.19 2008/03/06 00:34:11 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 "admin.h" 80#include "admin_var.h" 81#include "isakmp_inf.h" 82#ifdef ENABLE_HYBRID 83#include "isakmp_cfg.h" 84#endif 85#include "session.h" 86#include "gcmalloc.h" 87 88#ifdef ENABLE_ADMINPORT 89char *adminsock_path = ADMINSOCK_PATH; 90uid_t adminsock_owner = 0; 91gid_t adminsock_group = 0; 92mode_t adminsock_mode = 0600; 93 94static struct sockaddr_un sunaddr; 95static int admin_process __P((int, char *)); 96static int admin_reply __P((int, struct admin_com *, int, vchar_t *)); 97 98int 99admin_handler() 100{ 101 int so2; 102 struct sockaddr_storage from; 103 socklen_t fromlen = sizeof(from); 104 struct admin_com com; 105 char *combuf = NULL; 106 int len, error = -1; 107 108 so2 = accept(lcconf->sock_admin, (struct sockaddr *)&from, &fromlen); 109 if (so2 < 0) { 110 plog(LLV_ERROR, LOCATION, NULL, 111 "failed to accept admin command: %s\n", 112 strerror(errno)); 113 return -1; 114 } 115 116 /* get buffer length */ 117 while ((len = recv(so2, (char *)&com, sizeof(com), MSG_PEEK)) < 0) { 118 if (errno == EINTR) 119 continue; 120 plog(LLV_ERROR, LOCATION, NULL, 121 "failed to recv admin command: %s\n", 122 strerror(errno)); 123 goto end; 124 } 125 126 /* sanity check */ 127 if (len < sizeof(com)) { 128 plog(LLV_ERROR, LOCATION, NULL, 129 "invalid header length of admin command\n"); 130 goto end; 131 } 132 133 /* get buffer to receive */ 134 if ((combuf = racoon_malloc(com.ac_len)) == 0) { 135 plog(LLV_ERROR, LOCATION, NULL, 136 "failed to alloc buffer for admin command\n"); 137 goto end; 138 } 139 140 /* get real data */ 141 while ((len = recv(so2, combuf, com.ac_len, 0)) < 0) { 142 if (errno == EINTR) 143 continue; 144 plog(LLV_ERROR, LOCATION, NULL, 145 "failed to recv admin command: %s\n", 146 strerror(errno)); 147 goto end; 148 } 149 150 error = admin_process(so2, combuf); 151 152end: 153 if (error == -2) { 154 plog(LLV_DEBUG, LOCATION, NULL, 155 "[%d] admin connection established\n", so2); 156 } else { 157 (void)close(so2); 158 } 159 160 if (combuf) 161 racoon_free(combuf); 162 163 return error; 164} 165 166/* 167 * main child's process. 168 */ 169static int 170admin_process(so2, combuf) 171 int so2; 172 char *combuf; 173{ 174 struct admin_com *com = (struct admin_com *)combuf; 175 vchar_t *buf = NULL; 176 vchar_t *id = NULL; 177 vchar_t *key = NULL; 178 int idtype = 0; 179 int error = 0, ac_errno = 0; 180 struct evt_listener_list *event_list = NULL; 181 182 if (com->ac_cmd & ADMIN_FLAG_VERSION) 183 com->ac_cmd &= ~ADMIN_FLAG_VERSION; 184 else 185 com->ac_version = 0; 186 187 switch (com->ac_cmd) { 188 case ADMIN_RELOAD_CONF: 189 signal_handler(SIGHUP); 190 break; 191 192 case ADMIN_SHOW_SCHED: { 193 caddr_t p = NULL; 194 int len; 195 196 if (sched_dump(&p, &len) != -1) { 197 buf = vmalloc(len); 198 if (buf != NULL) 199 memcpy(buf->v, p, len); 200 else 201 ac_errno = ENOMEM; 202 racoon_free(p); 203 } else 204 ac_errno = ENOMEM; 205 break; 206 } 207 208 case ADMIN_SHOW_EVT: 209 if (com->ac_version == 0) { 210 buf = evt_dump(); 211 ac_errno = 0; 212 } 213 break; 214 215 case ADMIN_SHOW_SA: 216 case ADMIN_FLUSH_SA: 217 switch (com->ac_proto) { 218 case ADMIN_PROTO_ISAKMP: 219 switch (com->ac_cmd) { 220 case ADMIN_SHOW_SA: 221 buf = dumpph1(); 222 if (buf == NULL) 223 ac_errno = ENOMEM; 224 break; 225 case ADMIN_FLUSH_SA: 226 flushph1(); 227 break; 228 default: 229 ac_errno = ENOTSUP; 230 break; 231 } 232 break; 233 case ADMIN_PROTO_IPSEC: 234 case ADMIN_PROTO_AH: 235 case ADMIN_PROTO_ESP: 236 switch (com->ac_cmd) { 237 case ADMIN_SHOW_SA: { 238 u_int p; 239 p = admin2pfkey_proto(com->ac_proto); 240 if (p != -1) { 241 buf = pfkey_dump_sadb(p); 242 if (buf == NULL) 243 ac_errno = ENOMEM; 244 } else 245 ac_errno = EINVAL; 246 break; 247 } 248 case ADMIN_FLUSH_SA: 249 pfkey_flush_sadb(com->ac_proto); 250 break; 251 default: 252 ac_errno = ENOTSUP; 253 break; 254 } 255 break; 256 case ADMIN_PROTO_INTERNAL: 257 switch (com->ac_cmd) { 258 case ADMIN_SHOW_SA: 259 buf = NULL; /*XXX dumpph2(&error);*/ 260 ac_errno = ENOTSUP; 261 break; 262 case ADMIN_FLUSH_SA: 263 /*XXX flushph2();*/ 264 break; 265 default: 266 ac_errno = ENOTSUP; 267 break; 268 } 269 break; 270 default: 271 ac_errno = ENOTSUP; 272 } 273 break; 274 275 case ADMIN_DELETE_SA: { 276 struct ph1handle *iph1; 277 struct sockaddr *dst; 278 struct sockaddr *src; 279 char *loc, *rem; 280 281 src = (struct sockaddr *) 282 &((struct admin_com_indexes *) 283 ((caddr_t)com + sizeof(*com)))->src; 284 dst = (struct sockaddr *) 285 &((struct admin_com_indexes *) 286 ((caddr_t)com + sizeof(*com)))->dst; 287 288 loc = racoon_strdup(saddrwop2str(src)); 289 rem = racoon_strdup(saddrwop2str(dst)); 290 STRDUP_FATAL(loc); 291 STRDUP_FATAL(rem); 292 293 if ((iph1 = getph1byaddrwop(src, dst)) == NULL) { 294 plog(LLV_ERROR, LOCATION, NULL, 295 "phase 1 for %s -> %s not found\n", loc, rem); 296 } else { 297 if (iph1->status == PHASE1ST_ESTABLISHED) 298 isakmp_info_send_d1(iph1); 299 purge_remote(iph1); 300 } 301 302 racoon_free(loc); 303 racoon_free(rem); 304 break; 305 } 306 307#ifdef ENABLE_HYBRID 308 case ADMIN_LOGOUT_USER: { 309 struct ph1handle *iph1; 310 char *user; 311 int found = 0; 312 313 if (com->ac_len > sizeof(com) + LOGINLEN + 1) { 314 plog(LLV_ERROR, LOCATION, NULL, 315 "malformed message (login too long)\n"); 316 break; 317 } 318 319 user = (char *)(com + 1); 320 found = purgeph1bylogin(user); 321 plog(LLV_INFO, LOCATION, NULL, 322 "deleted %d SA for user \"%s\"\n", found, user); 323 324 break; 325 } 326#endif 327 328 case ADMIN_DELETE_ALL_SA_DST: { 329 struct ph1handle *iph1; 330 struct sockaddr *dst; 331 char *loc, *rem; 332 333 dst = (struct sockaddr *) 334 &((struct admin_com_indexes *) 335 ((caddr_t)com + sizeof(*com)))->dst; 336 337 rem = racoon_strdup(saddrwop2str(dst)); 338 STRDUP_FATAL(rem); 339 340 plog(LLV_INFO, LOCATION, NULL, 341 "Flushing all SAs for peer %s\n", rem); 342 343 while ((iph1 = getph1bydstaddrwop(dst)) != NULL) { 344 loc = racoon_strdup(saddrwop2str(iph1->local)); 345 STRDUP_FATAL(loc); 346 347 if (iph1->status == PHASE1ST_ESTABLISHED) 348 isakmp_info_send_d1(iph1); 349 purge_remote(iph1); 350 351 racoon_free(loc); 352 } 353 354 racoon_free(rem); 355 break; 356 } 357 358 case ADMIN_ESTABLISH_SA_PSK: { 359 struct admin_com_psk *acp; 360 char *data; 361 362 acp = (struct admin_com_psk *) 363 ((char *)com + sizeof(*com) + 364 sizeof(struct admin_com_indexes)); 365 366 idtype = acp->id_type; 367 368 if ((id = vmalloc(acp->id_len)) == NULL) { 369 plog(LLV_ERROR, LOCATION, NULL, 370 "cannot allocate memory: %s\n", 371 strerror(errno)); 372 break; 373 } 374 data = (char *)(acp + 1); 375 memcpy(id->v, data, id->l); 376 377 if ((key = vmalloc(acp->key_len)) == NULL) { 378 plog(LLV_ERROR, LOCATION, NULL, 379 "cannot allocate memory: %s\n", 380 strerror(errno)); 381 vfree(id); 382 id = NULL; 383 break; 384 } 385 data = (char *)(data + acp->id_len); 386 memcpy(key->v, data, key->l); 387 } 388 /* FALLTHROUGH */ 389 case ADMIN_ESTABLISH_SA: { 390 struct sockaddr *dst; 391 struct sockaddr *src; 392 src = (struct sockaddr *) 393 &((struct admin_com_indexes *) 394 ((caddr_t)com + sizeof(*com)))->src; 395 dst = (struct sockaddr *) 396 &((struct admin_com_indexes *) 397 ((caddr_t)com + sizeof(*com)))->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 ac_errno = ENOTSUP; 486 break; 487 default: 488 /* ignore */ 489 ac_errno = ENOTSUP; 490 } 491 break; 492 } 493 494 default: 495 plog(LLV_ERROR, LOCATION, NULL, 496 "invalid command: %d\n", com->ac_cmd); 497 ac_errno = ENOTSUP; 498 } 499 500 if ((error = admin_reply(so2, com, ac_errno, buf)) != 0) 501 goto out; 502 503 /* start pushing events if so requested */ 504 if ((ac_errno == 0) && 505 (com->ac_version >= 1) && 506 (com->ac_cmd == ADMIN_SHOW_EVT || event_list != NULL)) 507 error = evt_subscribe(event_list, so2); 508out: 509 if (buf != NULL) 510 vfree(buf); 511 512 return error; 513} 514 515static int 516admin_reply(so, req, ac_errno, buf) 517 int so, ac_errno; 518 struct admin_com *req; 519 vchar_t *buf; 520{ 521 int tlen; 522 struct admin_com *combuf; 523 char *retbuf = NULL; 524 525 if (buf != NULL) 526 tlen = sizeof(*combuf) + buf->l; 527 else 528 tlen = sizeof(*combuf); 529 530 retbuf = racoon_calloc(1, tlen); 531 if (retbuf == NULL) { 532 plog(LLV_ERROR, LOCATION, NULL, 533 "failed to allocate admin buffer\n"); 534 return -1; 535 } 536 537 combuf = (struct admin_com *) retbuf; 538 combuf->ac_len = tlen; 539 combuf->ac_cmd = req->ac_cmd & ~ADMIN_FLAG_VERSION; 540 combuf->ac_errno = ac_errno; 541 combuf->ac_proto = req->ac_proto; 542 543 if (buf != NULL) 544 memcpy(retbuf + sizeof(*combuf), buf->v, buf->l); 545 546 tlen = send(so, retbuf, tlen, 0); 547 racoon_free(retbuf); 548 if (tlen < 0) { 549 plog(LLV_ERROR, LOCATION, NULL, 550 "failed to send admin command: %s\n", 551 strerror(errno)); 552 return -1; 553 } 554 555 return 0; 556} 557 558/* ADMIN_PROTO -> SADB_SATYPE */ 559int 560admin2pfkey_proto(proto) 561 u_int proto; 562{ 563 switch (proto) { 564 case ADMIN_PROTO_IPSEC: 565 return SADB_SATYPE_UNSPEC; 566 case ADMIN_PROTO_AH: 567 return SADB_SATYPE_AH; 568 case ADMIN_PROTO_ESP: 569 return SADB_SATYPE_ESP; 570 default: 571 plog(LLV_ERROR, LOCATION, NULL, 572 "unsupported proto for admin: %d\n", proto); 573 return -1; 574 } 575 /*NOTREACHED*/ 576} 577 578int 579admin_init() 580{ 581 if (adminsock_path == NULL) { 582 lcconf->sock_admin = -1; 583 return 0; 584 } 585 586 memset(&sunaddr, 0, sizeof(sunaddr)); 587 sunaddr.sun_family = AF_UNIX; 588 snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), 589 "%s", adminsock_path); 590 591 lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0); 592 if (lcconf->sock_admin == -1) { 593 plog(LLV_ERROR, LOCATION, NULL, 594 "socket: %s\n", strerror(errno)); 595 return -1; 596 } 597 598 unlink(sunaddr.sun_path); 599 if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr, 600 sizeof(sunaddr)) != 0) { 601 plog(LLV_ERROR, LOCATION, NULL, 602 "bind(sockname:%s): %s\n", 603 sunaddr.sun_path, strerror(errno)); 604 (void)close(lcconf->sock_admin); 605 return -1; 606 } 607 608 if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) { 609 plog(LLV_ERROR, LOCATION, NULL, 610 "chown(%s, %d, %d): %s\n", 611 sunaddr.sun_path, adminsock_owner, 612 adminsock_group, strerror(errno)); 613 (void)close(lcconf->sock_admin); 614 return -1; 615 } 616 617 if (chmod(sunaddr.sun_path, adminsock_mode) != 0) { 618 plog(LLV_ERROR, LOCATION, NULL, 619 "chmod(%s, 0%03o): %s\n", 620 sunaddr.sun_path, adminsock_mode, strerror(errno)); 621 (void)close(lcconf->sock_admin); 622 return -1; 623 } 624 625 if (listen(lcconf->sock_admin, 5) != 0) { 626 plog(LLV_ERROR, LOCATION, NULL, 627 "listen(sockname:%s): %s\n", 628 sunaddr.sun_path, strerror(errno)); 629 (void)close(lcconf->sock_admin); 630 return -1; 631 } 632 plog(LLV_DEBUG, LOCATION, NULL, 633 "open %s as racoon management.\n", sunaddr.sun_path); 634 635 return 0; 636} 637 638int 639admin_close() 640{ 641 close(lcconf->sock_admin); 642 return 0; 643} 644#endif 645 646