1/* $KAME: admin.c,v 1.23 2001/06/01 10:12:55 sakane Exp $ */ 2 3/* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/types.h> 33#include <sys/param.h> 34#include <sys/socket.h> 35#include <sys/signal.h> 36#include <sys/un.h> 37 38#include <net/pfkeyv2.h> 39 40#include <netinet/in.h> 41 42#include <stdlib.h> 43#include <stdio.h> 44#include <string.h> 45#include <errno.h> 46#include <netdb.h> 47#ifdef HAVE_UNISTD_H 48#include <unistd.h> 49#endif 50 51#include "var.h" 52#include "misc.h" 53#include "vmbuf.h" 54#include "plog.h" 55#include "sockmisc.h" 56#include "debug.h" 57 58#include "schedule.h" 59#include "localconf.h" 60#include "remoteconf.h" 61#include "grabmyaddr.h" 62#include "isakmp_var.h" 63#include "isakmp.h" 64#include "oakley.h" 65#include "handler.h" 66#include "pfkey.h" 67#include "admin.h" 68#include "admin_var.h" 69#include "session.h" 70#include "gcmalloc.h" 71 72static struct sockaddr_un sunaddr; 73static int admin_process __P((int, char *)); 74static int admin_reply __P((int, struct admin_com *, vchar_t *)); 75 76int 77admin_handler() 78{ 79 int so2; 80 struct sockaddr_storage from; 81 int fromlen = sizeof(from); 82 struct admin_com com; 83 char *combuf = NULL; 84 pid_t pid = -1; 85 int len, error = -1; 86 87 so2 = accept(lcconf->sock_admin, (struct sockaddr *)&from, &fromlen); 88 if (so2 < 0) { 89 plog(LLV_ERROR, LOCATION, NULL, 90 "failed to accept admin command: %s\n", 91 strerror(errno)); 92 return -1; 93 } 94 95 /* get buffer length */ 96 while ((len = recv(so2, (char *)&com, sizeof(com), MSG_PEEK)) < 0) { 97 if (errno == EINTR) 98 continue; 99 plog(LLV_ERROR, LOCATION, NULL, 100 "failed to recv admin command: %s\n", 101 strerror(errno)); 102 goto end; 103 } 104 105 /* sanity check */ 106 if (len < sizeof(com)) { 107 plog(LLV_ERROR, LOCATION, NULL, 108 "invalid header length of admin command\n"); 109 goto end; 110 } 111 112 /* get buffer to receive */ 113 if ((combuf = racoon_malloc(com.ac_len)) == 0) { 114 plog(LLV_ERROR, LOCATION, NULL, 115 "failed to alloc buffer for admin command\n"); 116 goto end; 117 } 118 119 /* get real data */ 120 while ((len = recv(so2, combuf, com.ac_len, 0)) < 0) { 121 if (errno == EINTR) 122 continue; 123 plog(LLV_ERROR, LOCATION, NULL, 124 "failed to recv admin command: %s\n", 125 strerror(errno)); 126 goto end; 127 } 128 129 /* don't fork() because of reloading config. */ 130 if (com.ac_cmd == ADMIN_RELOAD_CONF) { 131 /* reload does not work at all! */ 132 signal_handler(SIGHUP); 133 goto end; 134 } 135 136 /* fork for processing */ 137 if (!f_foreground) { 138 if ((pid = fork()) < 0) { 139 plog(LLV_ERROR, LOCATION, NULL, 140 "failed to fork for admin processing: %s\n", 141 strerror(errno)); 142 goto end; 143 } 144 145 /* parant's process. */ 146 if (pid != 0) { 147 error = 0; 148 goto end; 149 } 150 151 /* child's process */ 152 admin_close(); 153 } 154 155 /* exit in this function. */ 156 error = admin_process(so2, combuf); 157 158 end: 159 (void)close(so2); 160 if (combuf) 161 racoon_free(combuf); 162 163 /* exit if child's process. */ 164 if (pid == 0 && !f_foreground) 165 exit(error); 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 int error = 0; 181 182 com->ac_errno = 0; 183 184 switch (com->ac_cmd) { 185 case ADMIN_RELOAD_CONF: 186 /* don't entered because of proccessing it in other place. */ 187 plog(LLV_ERROR, LOCATION, NULL, "should never reach here\n"); 188 goto bad; 189 190 case ADMIN_SHOW_SCHED: 191 { 192 caddr_t p; 193 int len; 194 if (sched_dump(&p, &len) == -1) 195 com->ac_errno = -1; 196 buf = vmalloc(len); 197 if (buf == NULL) 198 com->ac_errno = -1; 199 memcpy(buf->v, p, len); 200 } 201 break; 202 case ADMIN_SHOW_SA: 203 case ADMIN_FLUSH_SA: 204 { 205 switch (com->ac_proto) { 206 case ADMIN_PROTO_ISAKMP: 207 switch (com->ac_cmd) { 208 case ADMIN_SHOW_SA: 209 buf = dumpph1(); 210 if (buf == NULL) 211 com->ac_errno = -1; 212 break; 213 case ADMIN_FLUSH_SA: 214 flushph1(); 215 break; 216 } 217 break; 218 case ADMIN_PROTO_IPSEC: 219 case ADMIN_PROTO_AH: 220 case ADMIN_PROTO_ESP: 221 switch (com->ac_cmd) { 222 case ADMIN_SHOW_SA: 223 { 224 u_int p; 225 p = admin2pfkey_proto(com->ac_proto); 226 if (p == -1) 227 goto bad; 228 buf = pfkey_dump_sadb(p); 229 if (buf == NULL) 230 com->ac_errno = -1; 231 } 232 break; 233 case ADMIN_FLUSH_SA: 234 pfkey_flush_sadb(com->ac_proto); 235 break; 236 } 237 break; 238 239 case ADMIN_PROTO_INTERNAL: 240 switch (com->ac_cmd) { 241 case ADMIN_SHOW_SA: 242 buf = NULL; 243 if (buf == NULL) 244 com->ac_errno = error; 245 break; 246 case ADMIN_FLUSH_SA: 247 com->ac_errno = 0; 248 break; 249 } 250 break; 251 252 default: 253 /* ignore */ 254 com->ac_errno = -1; 255 } 256 } 257 break; 258 259 case ADMIN_DELETE_SA: 260 break; 261 262 case ADMIN_ESTABLISH_SA: 263 { 264 struct sockaddr *dst; 265 struct sockaddr *src; 266 src = (struct sockaddr *) 267 &((struct admin_com_indexes *) 268 ((caddr_t)com + sizeof(*com)))->src; 269 dst = (struct sockaddr *) 270 &((struct admin_com_indexes *) 271 ((caddr_t)com + sizeof(*com)))->dst; 272 273 switch (com->ac_proto) { 274 case ADMIN_PROTO_ISAKMP: 275 { 276 struct remoteconf *rmconf; 277 struct sockaddr *remote; 278 struct sockaddr *local; 279 280 /* search appropreate configuration */ 281 rmconf = getrmconf(dst); 282 if (rmconf == NULL) { 283 plog(LLV_ERROR, LOCATION, NULL, 284 "no configuration found " 285 "for %s\n", saddrwop2str(dst)); 286 com->ac_errno = -1; 287 break; 288 } 289 290 /* get remote IP address and port number. */ 291 remote = dupsaddr(dst); 292 if (remote == NULL) { 293 com->ac_errno = -1; 294 break; 295 } 296 switch (remote->sa_family) { 297 case AF_INET: 298 ((struct sockaddr_in *)remote)->sin_port = 299 ((struct sockaddr_in *)rmconf->remote)->sin_port; 300 break; 301#ifdef INET6 302 case AF_INET6: 303 ((struct sockaddr_in6 *)remote)->sin6_port = 304 ((struct sockaddr_in6 *)rmconf->remote)->sin6_port; 305 break; 306#endif 307 default: 308 plog(LLV_ERROR, LOCATION, NULL, 309 "invalid family: %d\n", 310 remote->sa_family); 311 com->ac_errno = -1; 312 break; 313 } 314 315 /* get local address */ 316 local = dupsaddr(src); 317 if (local == NULL) { 318 com->ac_errno = -1; 319 break; 320 } 321 switch (local->sa_family) { 322 case AF_INET: 323 ((struct sockaddr_in *)local)->sin_port = 324 getmyaddrsport(local); 325 break; 326#ifdef INET6 327 case AF_INET6: 328 ((struct sockaddr_in6 *)local)->sin6_port = 329 getmyaddrsport(local); 330 break; 331#endif 332 default: 333 plog(LLV_ERROR, LOCATION, NULL, 334 "invalid family: %d\n", 335 local->sa_family); 336 com->ac_errno = -1; 337 break; 338 } 339 340 341 plog(LLV_INFO, LOCATION, NULL, 342 "accept a request to establish IKE-SA: " 343 "%s\n", saddrwop2str(remote)); 344 345 /* begin ident mode */ 346 if (isakmp_ph1begin_i(rmconf, remote) < 0) { 347 com->ac_errno = -1; 348 break; 349 } 350 } 351 break; 352 case ADMIN_PROTO_AH: 353 case ADMIN_PROTO_ESP: 354 break; 355 default: 356 /* ignore */ 357 com->ac_errno = -1; 358 } 359 } 360 break; 361 362 default: 363 plog(LLV_ERROR, LOCATION, NULL, 364 "invalid command: %d\n", com->ac_cmd); 365 com->ac_errno = -1; 366 } 367 368 if (admin_reply(so2, com, buf) < 0) 369 goto bad; 370 371 if (buf != NULL) 372 vfree(buf); 373 374 return 0; 375 376 bad: 377 if (buf != NULL) 378 vfree(buf); 379 return -1; 380} 381 382static int 383admin_reply(so, combuf, buf) 384 int so; 385 struct admin_com *combuf; 386 vchar_t *buf; 387{ 388 int tlen; 389 char *retbuf = NULL; 390 391 if (buf != NULL) 392 tlen = sizeof(*combuf) + buf->l; 393 else 394 tlen = sizeof(*combuf); 395 396 retbuf = racoon_calloc(1, tlen); 397 if (retbuf == NULL) { 398 plog(LLV_ERROR, LOCATION, NULL, 399 "failed to allocate admin buffer\n"); 400 return -1; 401 } 402 403 memcpy(retbuf, combuf, sizeof(*combuf)); 404 ((struct admin_com *)retbuf)->ac_len = tlen; 405 406 if (buf != NULL) 407 memcpy(retbuf + sizeof(*combuf), buf->v, buf->l); 408 409 tlen = send(so, retbuf, tlen, 0); 410 racoon_free(retbuf); 411 if (tlen < 0) { 412 plog(LLV_ERROR, LOCATION, NULL, 413 "failed to send admin command: %s\n", 414 strerror(errno)); 415 return -1; 416 } 417 418 return 0; 419} 420 421/* ADMIN_PROTO -> SADB_SATYPE */ 422int 423admin2pfkey_proto(proto) 424 u_int proto; 425{ 426 switch (proto) { 427 case ADMIN_PROTO_IPSEC: 428 return SADB_SATYPE_UNSPEC; 429 case ADMIN_PROTO_AH: 430 return SADB_SATYPE_AH; 431 case ADMIN_PROTO_ESP: 432 return SADB_SATYPE_ESP; 433 default: 434 plog(LLV_ERROR, LOCATION, NULL, 435 "unsupported proto for admin: %d\n", proto); 436 return -1; 437 } 438 /*NOTREACHED*/ 439} 440 441int 442admin_init() 443{ 444 memset(&sunaddr, 0, sizeof(sunaddr)); 445 sunaddr.sun_family = AF_UNIX; 446 snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), 447 "%s", PORT_ADMIN); 448 449 lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0); 450 if (lcconf->sock_admin < 0) { 451 plog(LLV_ERROR, LOCATION, NULL, 452 "socket: %s\n", strerror(errno)); 453 return -1; 454 } 455 456 if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr, 457 sizeof(sunaddr)) < 0) { 458 plog(LLV_ERROR, LOCATION, NULL, 459 "bind(sockname:%s): %s\n", 460 sunaddr.sun_path, strerror(errno)); 461 (void)close(lcconf->sock_admin); 462 return -1; 463 } 464 465 if (listen(lcconf->sock_admin, 5) < 0) { 466 plog(LLV_ERROR, LOCATION, NULL, 467 "listen(sockname:%s): %s\n", 468 sunaddr.sun_path, strerror(errno)); 469 (void)close(lcconf->sock_admin); 470 return -1; 471 } 472 plog(LLV_DEBUG, LOCATION, NULL, 473 "open %s as racoon management.\n", sunaddr.sun_path); 474 475 return 0; 476} 477 478int 479admin_close() 480{ 481 close(lcconf->sock_admin); 482 unlink(sunaddr.sun_path); 483 return 0; 484} 485