admin.c revision 1.13
1/* $NetBSD: admin.c,v 1.13 2006/09/30 15:51:42 manu 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#ifndef HAVE_NETINET6_IPSEC 47#include <netinet/ipsec.h> 48#else 49#include <netinet6/ipsec.h> 50#endif 51 52 53#include <stdlib.h> 54#include <stdio.h> 55#include <string.h> 56#include <errno.h> 57#include <netdb.h> 58#ifdef HAVE_UNISTD_H 59#include <unistd.h> 60#endif 61#ifdef ENABLE_HYBRID 62#include <resolv.h> 63#endif 64 65#include "var.h" 66#include "misc.h" 67#include "vmbuf.h" 68#include "plog.h" 69#include "sockmisc.h" 70#include "debug.h" 71 72#include "schedule.h" 73#include "localconf.h" 74#include "remoteconf.h" 75#include "grabmyaddr.h" 76#include "isakmp_var.h" 77#include "isakmp.h" 78#include "oakley.h" 79#include "handler.h" 80#include "evt.h" 81#include "pfkey.h" 82#include "ipsec_doi.h" 83#include "admin.h" 84#include "admin_var.h" 85#include "isakmp_inf.h" 86#ifdef ENABLE_HYBRID 87#include "isakmp_cfg.h" 88#endif 89#include "session.h" 90#include "gcmalloc.h" 91 92#ifdef ENABLE_ADMINPORT 93char *adminsock_path = ADMINSOCK_PATH; 94uid_t adminsock_owner = 0; 95gid_t adminsock_group = 0; 96mode_t adminsock_mode = 0600; 97 98static struct sockaddr_un sunaddr; 99static int admin_process __P((int, char *)); 100static int admin_reply __P((int, struct admin_com *, vchar_t *)); 101 102int 103admin_handler() 104{ 105 int so2; 106 struct sockaddr_storage from; 107 socklen_t fromlen = sizeof(from); 108 struct admin_com com; 109 char *combuf = NULL; 110 int len, error = -1; 111 112 so2 = accept(lcconf->sock_admin, (struct sockaddr *)&from, &fromlen); 113 if (so2 < 0) { 114 plog(LLV_ERROR, LOCATION, NULL, 115 "failed to accept admin command: %s\n", 116 strerror(errno)); 117 return -1; 118 } 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 if (com.ac_cmd == ADMIN_RELOAD_CONF) { 155 /* reload does not work at all! */ 156 signal_handler(SIGHUP); 157 goto end; 158 } 159 160 error = admin_process(so2, combuf); 161 162 end: 163 (void)close(so2); 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 = -1; 184 185 com->ac_errno = 0; 186 187 switch (com->ac_cmd) { 188 case ADMIN_RELOAD_CONF: 189 /* don't entered because of proccessing it in other place. */ 190 plog(LLV_ERROR, LOCATION, NULL, "should never reach here\n"); 191 goto out; 192 193 case ADMIN_SHOW_SCHED: 194 { 195 caddr_t p; 196 int len; 197 if (sched_dump(&p, &len) == -1) { 198 com->ac_errno = -1; 199 break; 200 } 201 202 buf = vmalloc(len); 203 if (buf == NULL) { 204 com->ac_errno = -1; 205 break; 206 } 207 208 memcpy(buf->v, p, len); 209 racoon_free(p); 210 } 211 break; 212 213 case ADMIN_SHOW_EVT: 214 /* It's not really an error, don't force racoonctl to quit */ 215 if ((buf = evt_dump()) == NULL) 216 com->ac_errno = 0; 217 break; 218 219 case ADMIN_SHOW_SA: 220 case ADMIN_FLUSH_SA: 221 { 222 switch (com->ac_proto) { 223 case ADMIN_PROTO_ISAKMP: 224 switch (com->ac_cmd) { 225 case ADMIN_SHOW_SA: 226 buf = dumpph1(); 227 if (buf == NULL) 228 com->ac_errno = -1; 229 break; 230 case ADMIN_FLUSH_SA: 231 flushph1(); 232 break; 233 } 234 break; 235 case ADMIN_PROTO_IPSEC: 236 case ADMIN_PROTO_AH: 237 case ADMIN_PROTO_ESP: 238 switch (com->ac_cmd) { 239 case ADMIN_SHOW_SA: 240 { 241 u_int p; 242 p = admin2pfkey_proto(com->ac_proto); 243 if (p == -1) 244 goto out; 245 buf = pfkey_dump_sadb(p); 246 if (buf == NULL) 247 com->ac_errno = -1; 248 } 249 break; 250 case ADMIN_FLUSH_SA: 251 pfkey_flush_sadb(com->ac_proto); 252 break; 253 } 254 break; 255 256 case ADMIN_PROTO_INTERNAL: 257 switch (com->ac_cmd) { 258 case ADMIN_SHOW_SA: 259 buf = NULL; /*XXX dumpph2(&error);*/ 260 if (buf == NULL) 261 com->ac_errno = error; 262 break; 263 case ADMIN_FLUSH_SA: 264 /*XXX flushph2();*/ 265 com->ac_errno = 0; 266 break; 267 } 268 break; 269 270 default: 271 /* ignore */ 272 com->ac_errno = -1; 273 } 274 } 275 break; 276 277 case ADMIN_DELETE_SA: { 278 struct ph1handle *iph1; 279 struct sockaddr *dst; 280 struct sockaddr *src; 281 char *loc, *rem; 282 283 src = (struct sockaddr *) 284 &((struct admin_com_indexes *) 285 ((caddr_t)com + sizeof(*com)))->src; 286 dst = (struct sockaddr *) 287 &((struct admin_com_indexes *) 288 ((caddr_t)com + sizeof(*com)))->dst; 289 290 loc = racoon_strdup(saddrwop2str(src)); 291 rem = racoon_strdup(saddrwop2str(dst)); 292 STRDUP_FATAL(loc); 293 STRDUP_FATAL(rem); 294 295 if ((iph1 = getph1byaddrwop(src, dst)) == NULL) { 296 plog(LLV_ERROR, LOCATION, NULL, 297 "phase 1 for %s -> %s not found\n", loc, rem); 298 } else { 299 if (iph1->status == PHASE1ST_ESTABLISHED) 300 isakmp_info_send_d1(iph1); 301 purge_remote(iph1); 302 } 303 304 racoon_free(loc); 305 racoon_free(rem); 306 307 break; 308 } 309 310#ifdef ENABLE_HYBRID 311 case ADMIN_LOGOUT_USER: { 312 struct ph1handle *iph1; 313 char *user; 314 int found = 0; 315 316 if (com->ac_len > sizeof(com) + LOGINLEN + 1) { 317 plog(LLV_ERROR, LOCATION, NULL, 318 "malformed message (login too long)\n"); 319 break; 320 } 321 322 user = (char *)(com + 1); 323 found = purgeph1bylogin(user); 324 plog(LLV_INFO, LOCATION, NULL, 325 "deleted %d SA for user \"%s\"\n", found, user); 326 327 break; 328 } 329#endif 330 331 case ADMIN_DELETE_ALL_SA_DST: { 332 struct ph1handle *iph1; 333 struct sockaddr *dst; 334 char *loc, *rem; 335 336 dst = (struct sockaddr *) 337 &((struct admin_com_indexes *) 338 ((caddr_t)com + sizeof(*com)))->dst; 339 340 rem = racoon_strdup(saddrwop2str(dst)); 341 STRDUP_FATAL(rem); 342 343 plog(LLV_INFO, LOCATION, NULL, 344 "Flushing all SAs for peer %s\n", rem); 345 346 while ((iph1 = getph1bydstaddrwop(dst)) != NULL) { 347 loc = racoon_strdup(saddrwop2str(iph1->local)); 348 STRDUP_FATAL(loc); 349 350 if (iph1->status == PHASE1ST_ESTABLISHED) 351 isakmp_info_send_d1(iph1); 352 purge_remote(iph1); 353 354 racoon_free(loc); 355 } 356 357 racoon_free(rem); 358 359 break; 360 } 361 362 case ADMIN_ESTABLISH_SA_PSK: { 363 struct admin_com_psk *acp; 364 char *data; 365 366 com->ac_cmd = ADMIN_ESTABLISH_SA; 367 368 acp = (struct admin_com_psk *) 369 ((char *)com + sizeof(*com) + 370 sizeof(struct admin_com_indexes)); 371 372 idtype = acp->id_type; 373 374 if ((id = vmalloc(acp->id_len)) == NULL) { 375 plog(LLV_ERROR, LOCATION, NULL, 376 "cannot allocate memory: %s\n", 377 strerror(errno)); 378 break; 379 } 380 data = (char *)(acp + 1); 381 memcpy(id->v, data, id->l); 382 383 if ((key = vmalloc(acp->key_len)) == NULL) { 384 plog(LLV_ERROR, LOCATION, NULL, 385 "cannot allocate memory: %s\n", 386 strerror(errno)); 387 vfree(id); 388 break; 389 } 390 data = (char *)(data + acp->id_len); 391 memcpy(key->v, data, key->l); 392 } 393 /* FALLTHROUGH */ 394 case ADMIN_ESTABLISH_SA: 395 { 396 struct sockaddr *dst; 397 struct sockaddr *src; 398 src = (struct sockaddr *) 399 &((struct admin_com_indexes *) 400 ((caddr_t)com + sizeof(*com)))->src; 401 dst = (struct sockaddr *) 402 &((struct admin_com_indexes *) 403 ((caddr_t)com + sizeof(*com)))->dst; 404 405 switch (com->ac_proto) { 406 case ADMIN_PROTO_ISAKMP: 407 { 408 struct remoteconf *rmconf; 409 struct sockaddr *remote; 410 struct sockaddr *local; 411 412 /* search appropreate configuration */ 413 rmconf = getrmconf(dst); 414 if (rmconf == NULL) { 415 plog(LLV_ERROR, LOCATION, NULL, 416 "no configuration found " 417 "for %s\n", saddrwop2str(dst)); 418 com->ac_errno = -1; 419 break; 420 } 421 422 /* get remote IP address and port number. */ 423 remote = dupsaddr(dst); 424 if (remote == NULL) { 425 com->ac_errno = -1; 426 break; 427 } 428 switch (remote->sa_family) { 429 case AF_INET: 430 ((struct sockaddr_in *)remote)->sin_port = 431 ((struct sockaddr_in *)rmconf->remote)->sin_port; 432 break; 433#ifdef INET6 434 case AF_INET6: 435 ((struct sockaddr_in6 *)remote)->sin6_port = 436 ((struct sockaddr_in6 *)rmconf->remote)->sin6_port; 437 break; 438#endif 439 default: 440 plog(LLV_ERROR, LOCATION, NULL, 441 "invalid family: %d\n", 442 remote->sa_family); 443 com->ac_errno = -1; 444 break; 445 } 446 447 /* get local address */ 448 local = dupsaddr(src); 449 if (local == NULL) { 450 com->ac_errno = -1; 451 break; 452 } 453 switch (local->sa_family) { 454 case AF_INET: 455 ((struct sockaddr_in *)local)->sin_port = 456 getmyaddrsport(local); 457 break; 458#ifdef INET6 459 case AF_INET6: 460 ((struct sockaddr_in6 *)local)->sin6_port = 461 getmyaddrsport(local); 462 break; 463#endif 464 default: 465 plog(LLV_ERROR, LOCATION, NULL, 466 "invalid family: %d\n", 467 local->sa_family); 468 com->ac_errno = -1; 469 break; 470 } 471 472#ifdef ENABLE_HYBRID 473 /* Set the id and key */ 474 if (id && key) { 475 if (xauth_rmconf_used(&rmconf->xauth) == -1) { 476 com->ac_errno = -1; 477 break; 478 } 479 480 if (rmconf->xauth->login != NULL) { 481 vfree(rmconf->xauth->login); 482 rmconf->xauth->login = NULL; 483 } 484 if (rmconf->xauth->pass != NULL) { 485 vfree(rmconf->xauth->pass); 486 rmconf->xauth->pass = NULL; 487 } 488 489 rmconf->xauth->login = id; 490 rmconf->xauth->pass = key; 491 } 492#endif 493 494 plog(LLV_INFO, LOCATION, NULL, 495 "accept a request to establish IKE-SA: " 496 "%s\n", saddrwop2str(remote)); 497 498 /* begin ident mode */ 499 if (isakmp_ph1begin_i(rmconf, remote, local) < 0) { 500 com->ac_errno = -1; 501 break; 502 } 503 } 504 break; 505 case ADMIN_PROTO_AH: 506 case ADMIN_PROTO_ESP: 507 break; 508 default: 509 /* ignore */ 510 com->ac_errno = -1; 511 } 512 } 513 break; 514 515 default: 516 plog(LLV_ERROR, LOCATION, NULL, 517 "invalid command: %d\n", com->ac_cmd); 518 com->ac_errno = -1; 519 } 520 521 if ((error = admin_reply(so2, com, buf)) != 0) 522 goto out; 523 524 error = 0; 525out: 526 if (buf != NULL) 527 vfree(buf); 528 529 return error; 530} 531 532static int 533admin_reply(so, combuf, buf) 534 int so; 535 struct admin_com *combuf; 536 vchar_t *buf; 537{ 538 int tlen; 539 char *retbuf = NULL; 540 541 if (buf != NULL) 542 tlen = sizeof(*combuf) + buf->l; 543 else 544 tlen = sizeof(*combuf); 545 546 retbuf = racoon_calloc(1, tlen); 547 if (retbuf == NULL) { 548 plog(LLV_ERROR, LOCATION, NULL, 549 "failed to allocate admin buffer\n"); 550 return -1; 551 } 552 553 memcpy(retbuf, combuf, sizeof(*combuf)); 554 ((struct admin_com *)retbuf)->ac_len = tlen; 555 556 if (buf != NULL) 557 memcpy(retbuf + sizeof(*combuf), buf->v, buf->l); 558 559 tlen = send(so, retbuf, tlen, 0); 560 racoon_free(retbuf); 561 if (tlen < 0) { 562 plog(LLV_ERROR, LOCATION, NULL, 563 "failed to send admin command: %s\n", 564 strerror(errno)); 565 return -1; 566 } 567 568 return 0; 569} 570 571/* ADMIN_PROTO -> SADB_SATYPE */ 572int 573admin2pfkey_proto(proto) 574 u_int proto; 575{ 576 switch (proto) { 577 case ADMIN_PROTO_IPSEC: 578 return SADB_SATYPE_UNSPEC; 579 case ADMIN_PROTO_AH: 580 return SADB_SATYPE_AH; 581 case ADMIN_PROTO_ESP: 582 return SADB_SATYPE_ESP; 583 default: 584 plog(LLV_ERROR, LOCATION, NULL, 585 "unsupported proto for admin: %d\n", proto); 586 return -1; 587 } 588 /*NOTREACHED*/ 589} 590 591int 592admin_init() 593{ 594 if (adminsock_path == NULL) { 595 lcconf->sock_admin = -1; 596 return 0; 597 } 598 599 memset(&sunaddr, 0, sizeof(sunaddr)); 600 sunaddr.sun_family = AF_UNIX; 601 snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), 602 "%s", adminsock_path); 603 604 lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0); 605 if (lcconf->sock_admin == -1) { 606 plog(LLV_ERROR, LOCATION, NULL, 607 "socket: %s\n", strerror(errno)); 608 return -1; 609 } 610 611 unlink(sunaddr.sun_path); 612 if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr, 613 sizeof(sunaddr)) != 0) { 614 plog(LLV_ERROR, LOCATION, NULL, 615 "bind(sockname:%s): %s\n", 616 sunaddr.sun_path, strerror(errno)); 617 (void)close(lcconf->sock_admin); 618 return -1; 619 } 620 621 if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) { 622 plog(LLV_ERROR, LOCATION, NULL, 623 "chown(%s, %d, %d): %s\n", 624 sunaddr.sun_path, adminsock_owner, 625 adminsock_group, strerror(errno)); 626 (void)close(lcconf->sock_admin); 627 return -1; 628 } 629 630 if (chmod(sunaddr.sun_path, adminsock_mode) != 0) { 631 plog(LLV_ERROR, LOCATION, NULL, 632 "chmod(%s, 0%03o): %s\n", 633 sunaddr.sun_path, adminsock_mode, strerror(errno)); 634 (void)close(lcconf->sock_admin); 635 return -1; 636 } 637 638 if (listen(lcconf->sock_admin, 5) != 0) { 639 plog(LLV_ERROR, LOCATION, NULL, 640 "listen(sockname:%s): %s\n", 641 sunaddr.sun_path, strerror(errno)); 642 (void)close(lcconf->sock_admin); 643 return -1; 644 } 645 plog(LLV_DEBUG, LOCATION, NULL, 646 "open %s as racoon management.\n", sunaddr.sun_path); 647 648 return 0; 649} 650 651int 652admin_close() 653{ 654 close(lcconf->sock_admin); 655 return 0; 656} 657#endif 658 659