Home | History | Annotate | Download | only in racoon
      1 /*	$NetBSD: admin.c,v 1.17.6.3 2009/04/20 13:32:57 tteras 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
     89 char *adminsock_path = ADMINSOCK_PATH;
     90 uid_t adminsock_owner = 0;
     91 gid_t adminsock_group = 0;
     92 mode_t adminsock_mode = 0600;
     93 
     94 static struct sockaddr_un sunaddr;
     95 static int admin_process __P((int, char *));
     96 static int admin_reply __P((int, struct admin_com *, vchar_t *));
     97 
     98 int
     99 admin_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 	if (com.ac_cmd == ADMIN_RELOAD_CONF) {
    151 		/* reload does not work at all! */
    152 		signal_handler(SIGHUP);
    153 		goto end;
    154 	}
    155 
    156 	error = admin_process(so2, combuf);
    157 
    158     end:
    159 	(void)close(so2);
    160 	if (combuf)
    161 		racoon_free(combuf);
    162 
    163 	return error;
    164 }
    165 
    166 /*
    167  * main child's process.
    168  */
    169 static int
    170 admin_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 = -1;
    180 
    181 	com->ac_errno = 0;
    182 
    183 	switch (com->ac_cmd) {
    184 	case ADMIN_RELOAD_CONF:
    185 		/* don't entered because of proccessing it in other place. */
    186 		plog(LLV_ERROR, LOCATION, NULL, "should never reach here\n");
    187 		goto out;
    188 
    189 	case ADMIN_SHOW_SCHED:
    190 	{
    191 		caddr_t p = NULL;
    192 		int len;
    193 
    194 		com->ac_errno = -1;
    195 
    196 		if (sched_dump(&p, &len) == -1)
    197 			goto out2;
    198 
    199 		if ((buf = vmalloc(len)) == NULL)
    200 			goto out2;
    201 
    202 		memcpy(buf->v, p, len);
    203 
    204 		com->ac_errno = 0;
    205 out2:
    206 		racoon_free(p);
    207 		break;
    208 	}
    209 
    210 	case ADMIN_SHOW_EVT:
    211 		/* It's not really an error, don't force racoonctl to quit */
    212 		if ((buf = evt_dump()) == NULL)
    213 			com->ac_errno = 0;
    214 		break;
    215 
    216 	case ADMIN_SHOW_SA:
    217 	case ADMIN_FLUSH_SA:
    218 	    {
    219 		switch (com->ac_proto) {
    220 		case ADMIN_PROTO_ISAKMP:
    221 			switch (com->ac_cmd) {
    222 			case ADMIN_SHOW_SA:
    223 				buf = dumpph1();
    224 				if (buf == NULL)
    225 					com->ac_errno = -1;
    226 				break;
    227 			case ADMIN_FLUSH_SA:
    228 				flushph1();
    229 				break;
    230 			}
    231 			break;
    232 		case ADMIN_PROTO_IPSEC:
    233 		case ADMIN_PROTO_AH:
    234 		case ADMIN_PROTO_ESP:
    235 			switch (com->ac_cmd) {
    236 			case ADMIN_SHOW_SA:
    237 			    {
    238 				u_int p;
    239 				p = admin2pfkey_proto(com->ac_proto);
    240 				if (p == -1)
    241 					goto out;
    242 				buf = pfkey_dump_sadb(p);
    243 				if (buf == NULL)
    244 					com->ac_errno = -1;
    245 			    }
    246 				break;
    247 			case ADMIN_FLUSH_SA:
    248 				pfkey_flush_sadb(com->ac_proto);
    249 				break;
    250 			}
    251 			break;
    252 
    253 		case ADMIN_PROTO_INTERNAL:
    254 			switch (com->ac_cmd) {
    255 			case ADMIN_SHOW_SA:
    256 				buf = NULL; /*XXX dumpph2(&error);*/
    257 				if (buf == NULL)
    258 					com->ac_errno = error;
    259 				break;
    260 			case ADMIN_FLUSH_SA:
    261 				/*XXX flushph2();*/
    262 				com->ac_errno = 0;
    263 				break;
    264 			}
    265 			break;
    266 
    267 		default:
    268 			/* ignore */
    269 			com->ac_errno = -1;
    270 		}
    271 	    }
    272 		break;
    273 
    274 	case ADMIN_DELETE_SA: {
    275 		struct ph1handle *iph1;
    276 		struct sockaddr *dst;
    277 		struct sockaddr *src;
    278 		char *loc, *rem;
    279 
    280 		src = (struct sockaddr *)
    281 			&((struct admin_com_indexes *)
    282 			    ((caddr_t)com + sizeof(*com)))->src;
    283 		dst = (struct sockaddr *)
    284 			&((struct admin_com_indexes *)
    285 			    ((caddr_t)com + sizeof(*com)))->dst;
    286 
    287 		loc = racoon_strdup(saddrwop2str(src));
    288 		rem = racoon_strdup(saddrwop2str(dst));
    289 		STRDUP_FATAL(loc);
    290 		STRDUP_FATAL(rem);
    291 
    292 		if ((iph1 = getph1byaddrwop(src, dst)) == NULL) {
    293 			plog(LLV_ERROR, LOCATION, NULL,
    294 			    "phase 1 for %s -> %s not found\n", loc, rem);
    295 		} else {
    296 			if (iph1->status == PHASE1ST_ESTABLISHED)
    297 				isakmp_info_send_d1(iph1);
    298 			purge_remote(iph1);
    299 		}
    300 
    301 		racoon_free(loc);
    302 		racoon_free(rem);
    303 
    304 		break;
    305 	}
    306 
    307 #ifdef ENABLE_HYBRID
    308 	case ADMIN_LOGOUT_USER: {
    309 		struct ph1handle *iph1;
    310 		char user[LOGINLEN+1];
    311 		int found = 0, len = com->ac_len - sizeof(com);
    312 
    313 		if (len > LOGINLEN) {
    314 			plog(LLV_ERROR, LOCATION, NULL,
    315 			    "malformed message (login too long)\n");
    316 			break;
    317 		}
    318 
    319 		memcpy(user, (char *)(com + 1), len);
    320 		user[len] = 0;
    321 
    322 		found = purgeph1bylogin(user);
    323 		plog(LLV_INFO, LOCATION, NULL,
    324 		    "deleted %d SA for user \"%s\"\n", found, user);
    325 
    326 		break;
    327 	}
    328 #endif
    329 
    330 	case ADMIN_DELETE_ALL_SA_DST: {
    331 		struct ph1handle *iph1;
    332 		struct sockaddr *dst;
    333 		char *loc, *rem;
    334 
    335 		dst = (struct sockaddr *)
    336 			&((struct admin_com_indexes *)
    337 			    ((caddr_t)com + sizeof(*com)))->dst;
    338 
    339 		rem = racoon_strdup(saddrwop2str(dst));
    340 		STRDUP_FATAL(rem);
    341 
    342 		plog(LLV_INFO, LOCATION, NULL,
    343 		    "Flushing all SAs for peer %s\n", rem);
    344 
    345 		while ((iph1 = getph1bydstaddrwop(dst)) != NULL) {
    346 			loc = racoon_strdup(saddrwop2str(iph1->local));
    347 			STRDUP_FATAL(loc);
    348 
    349 			if (iph1->status == PHASE1ST_ESTABLISHED)
    350 				isakmp_info_send_d1(iph1);
    351 			purge_remote(iph1);
    352 
    353 			racoon_free(loc);
    354 		}
    355 
    356 		racoon_free(rem);
    357 
    358 		break;
    359 	}
    360 
    361 	case ADMIN_ESTABLISH_SA_PSK: {
    362 		struct admin_com_psk *acp;
    363 		char *data;
    364 
    365 		com->ac_cmd = ADMIN_ESTABLISH_SA;
    366 
    367 		acp = (struct admin_com_psk *)
    368 		    ((char *)com + sizeof(*com) +
    369 		    sizeof(struct admin_com_indexes));
    370 
    371 		idtype = acp->id_type;
    372 
    373 		if ((id = vmalloc(acp->id_len)) == NULL) {
    374 			plog(LLV_ERROR, LOCATION, NULL,
    375 			    "cannot allocate memory: %s\n",
    376 			    strerror(errno));
    377 			break;
    378 		}
    379 		data = (char *)(acp + 1);
    380 		memcpy(id->v, data, id->l);
    381 
    382 		if ((key = vmalloc(acp->key_len)) == NULL) {
    383 			plog(LLV_ERROR, LOCATION, NULL,
    384 			    "cannot allocate memory: %s\n",
    385 			    strerror(errno));
    386 			vfree(id);
    387 			id = NULL;
    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 			struct remoteconf *rmconf;
    408 			struct sockaddr *remote = NULL;
    409 			struct sockaddr *local = NULL;
    410 			u_int16_t port;
    411 
    412 			com->ac_errno = -1;
    413 
    414 			/* search appropreate configuration */
    415 			rmconf = getrmconf(dst);
    416 			if (rmconf == NULL) {
    417 				plog(LLV_ERROR, LOCATION, NULL,
    418 					"no configuration found "
    419 					"for %s\n", saddrwop2str(dst));
    420 				goto out1;
    421 			}
    422 
    423 			/* get remote IP address and port number. */
    424 			if ((remote = dupsaddr(dst)) == NULL)
    425 				goto out1;
    426 
    427 			port = extract_port(rmconf->remote);
    428 			if (set_port(remote, port) == NULL)
    429 				goto out1;
    430 
    431 			/* get local address */
    432 			if ((local = dupsaddr(src)) == NULL)
    433 				goto out1;
    434 
    435 			port = getmyaddrsport(local);
    436 			if (set_port(local, port) == NULL)
    437 				goto out1;
    438 
    439 #ifdef ENABLE_HYBRID
    440 			/* Set the id and key */
    441 			if (id && key) {
    442 				if (xauth_rmconf_used(&rmconf->xauth) == -1)
    443 					goto out1;
    444 
    445 				if (rmconf->xauth->login != NULL) {
    446 					vfree(rmconf->xauth->login);
    447 					rmconf->xauth->login = NULL;
    448 				}
    449 				if (rmconf->xauth->pass != NULL) {
    450 					vfree(rmconf->xauth->pass);
    451 					rmconf->xauth->pass = NULL;
    452 				}
    453 
    454 				rmconf->xauth->login = id;
    455 				rmconf->xauth->pass = key;
    456 			}
    457 #endif
    458 
    459 			plog(LLV_INFO, LOCATION, NULL,
    460 				"accept a request to establish IKE-SA: "
    461 				"%s\n", saddrwop2str(remote));
    462 
    463 			/* begin ident mode */
    464 			if (isakmp_ph1begin_i(rmconf, remote, local) < 0)
    465 				goto out1;
    466 
    467 			com->ac_errno = 0;
    468 out1:
    469 			if (local != NULL)
    470 				racoon_free(local);
    471 			if (remote != NULL)
    472 				racoon_free(remote);
    473 			break;
    474 		}
    475 		case ADMIN_PROTO_AH:
    476 		case ADMIN_PROTO_ESP:
    477 			break;
    478 		default:
    479 			/* ignore */
    480 			com->ac_errno = -1;
    481 		}
    482 	    }
    483 		break;
    484 
    485 	default:
    486 		plog(LLV_ERROR, LOCATION, NULL,
    487 			"invalid command: %d\n", com->ac_cmd);
    488 		com->ac_errno = -1;
    489 	}
    490 
    491 	if ((error = admin_reply(so2, com, buf)) != 0)
    492 		goto out;
    493 
    494 	error = 0;
    495 out:
    496 	if (buf != NULL)
    497 		vfree(buf);
    498 
    499 	return error;
    500 }
    501 
    502 static int
    503 admin_reply(so, combuf, buf)
    504 	int so;
    505 	struct admin_com *combuf;
    506 	vchar_t *buf;
    507 {
    508 	int tlen;
    509 	char *retbuf = NULL;
    510 
    511 	if (buf != NULL)
    512 		tlen = sizeof(*combuf) + buf->l;
    513 	else
    514 		tlen = sizeof(*combuf);
    515 
    516 	retbuf = racoon_calloc(1, tlen);
    517 	if (retbuf == NULL) {
    518 		plog(LLV_ERROR, LOCATION, NULL,
    519 			"failed to allocate admin buffer\n");
    520 		return -1;
    521 	}
    522 
    523 	memcpy(retbuf, combuf, sizeof(*combuf));
    524 	((struct admin_com *)retbuf)->ac_len = tlen;
    525 
    526 	if (buf != NULL)
    527 		memcpy(retbuf + sizeof(*combuf), buf->v, buf->l);
    528 
    529 	tlen = send(so, retbuf, tlen, 0);
    530 	racoon_free(retbuf);
    531 	if (tlen < 0) {
    532 		plog(LLV_ERROR, LOCATION, NULL,
    533 			"failed to send admin command: %s\n",
    534 			strerror(errno));
    535 		return -1;
    536 	}
    537 
    538 	return 0;
    539 }
    540 
    541 /* ADMIN_PROTO -> SADB_SATYPE */
    542 int
    543 admin2pfkey_proto(proto)
    544 	u_int proto;
    545 {
    546 	switch (proto) {
    547 	case ADMIN_PROTO_IPSEC:
    548 		return SADB_SATYPE_UNSPEC;
    549 	case ADMIN_PROTO_AH:
    550 		return SADB_SATYPE_AH;
    551 	case ADMIN_PROTO_ESP:
    552 		return SADB_SATYPE_ESP;
    553 	default:
    554 		plog(LLV_ERROR, LOCATION, NULL,
    555 			"unsupported proto for admin: %d\n", proto);
    556 		return -1;
    557 	}
    558 	/*NOTREACHED*/
    559 }
    560 
    561 int
    562 admin_init()
    563 {
    564 	if (adminsock_path == NULL) {
    565 		lcconf->sock_admin = -1;
    566 		return 0;
    567 	}
    568 
    569 	memset(&sunaddr, 0, sizeof(sunaddr));
    570 	sunaddr.sun_family = AF_UNIX;
    571 	snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
    572 		"%s", adminsock_path);
    573 
    574 	lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0);
    575 	if (lcconf->sock_admin == -1) {
    576 		plog(LLV_ERROR, LOCATION, NULL,
    577 			"socket: %s\n", strerror(errno));
    578 		return -1;
    579 	}
    580 
    581 	unlink(sunaddr.sun_path);
    582 	if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr,
    583 			sizeof(sunaddr)) != 0) {
    584 		plog(LLV_ERROR, LOCATION, NULL,
    585 			"bind(sockname:%s): %s\n",
    586 			sunaddr.sun_path, strerror(errno));
    587 		(void)close(lcconf->sock_admin);
    588 		return -1;
    589 	}
    590 
    591 	if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) {
    592 		plog(LLV_ERROR, LOCATION, NULL,
    593 		    "chown(%s, %d, %d): %s\n",
    594 		    sunaddr.sun_path, adminsock_owner,
    595 		    adminsock_group, strerror(errno));
    596 		(void)close(lcconf->sock_admin);
    597 		return -1;
    598 	}
    599 
    600 	if (chmod(sunaddr.sun_path, adminsock_mode) != 0) {
    601 		plog(LLV_ERROR, LOCATION, NULL,
    602 		    "chmod(%s, 0%03o): %s\n",
    603 		    sunaddr.sun_path, adminsock_mode, strerror(errno));
    604 		(void)close(lcconf->sock_admin);
    605 		return -1;
    606 	}
    607 
    608 	if (listen(lcconf->sock_admin, 5) != 0) {
    609 		plog(LLV_ERROR, LOCATION, NULL,
    610 			"listen(sockname:%s): %s\n",
    611 			sunaddr.sun_path, strerror(errno));
    612 		(void)close(lcconf->sock_admin);
    613 		return -1;
    614 	}
    615 	plog(LLV_DEBUG, LOCATION, NULL,
    616 		"open %s as racoon management.\n", sunaddr.sun_path);
    617 
    618 	return 0;
    619 }
    620 
    621 int
    622 admin_close()
    623 {
    624 	close(lcconf->sock_admin);
    625 	return 0;
    626 }
    627 #endif
    628 
    629