Home | History | Annotate | Download | only in racoon
      1 /*	$NetBSD: admin.c,v 1.38 2010/12/08 07:38:35 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 "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
     90 char *adminsock_path = ADMINSOCK_PATH;
     91 uid_t adminsock_owner = 0;
     92 gid_t adminsock_group = 0;
     93 mode_t adminsock_mode = 0600;
     94 
     95 static struct sockaddr_un sunaddr;
     96 static int admin_process __P((int, char *));
     97 static int admin_reply __P((int, struct admin_com *, int, vchar_t *));
     98 
     99 static int
    100 admin_handler(ctx, fd)
    101 	void *ctx;
    102 	int fd;
    103 {
    104 	int so2;
    105 	struct sockaddr_storage from;
    106 	socklen_t fromlen = sizeof(from);
    107 	struct admin_com com;
    108 	char *combuf = NULL;
    109 	int len, error = -1;
    110 
    111 	so2 = accept(lcconf->sock_admin, (struct sockaddr *)&from, &fromlen);
    112 	if (so2 < 0) {
    113 		plog(LLV_ERROR, LOCATION, NULL,
    114 			"failed to accept admin command: %s\n",
    115 			strerror(errno));
    116 		return -1;
    117 	}
    118 	close_on_exec(so2);
    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 	error = admin_process(so2, combuf);
    155 
    156 end:
    157 	if (error == -2) {
    158 		plog(LLV_DEBUG, LOCATION, NULL,
    159 			"[%d] admin connection established\n", so2);
    160 	} else {
    161 		(void)close(so2);
    162 	}
    163 
    164 	if (combuf)
    165 		racoon_free(combuf);
    166 
    167 	return error;
    168 }
    169 
    170 static int admin_ph1_delete_sa(struct ph1handle *iph1, void *arg)
    171 {
    172 	if (iph1->status >= PHASE1ST_ESTABLISHED)
    173 		isakmp_info_send_d1(iph1);
    174 	purge_remote(iph1);
    175 	return 0;
    176 }
    177 
    178 /*
    179  * main child's process.
    180  */
    181 static int
    182 admin_process(so2, combuf)
    183 	int so2;
    184 	char *combuf;
    185 {
    186 	struct admin_com *com = (struct admin_com *)combuf;
    187 	vchar_t *buf = NULL;
    188 	vchar_t *id = NULL;
    189 	vchar_t *key = NULL;
    190 	int idtype = 0;
    191 	int error = 0, l_ac_errno = 0;
    192 	struct evt_listener_list *event_list = NULL;
    193 
    194 	if (com->ac_cmd & ADMIN_FLAG_VERSION)
    195 		com->ac_cmd &= ~ADMIN_FLAG_VERSION;
    196 	else
    197 		com->ac_version = 0;
    198 
    199 	switch (com->ac_cmd) {
    200 	case ADMIN_RELOAD_CONF:
    201 		signal_handler(SIGHUP);
    202 		break;
    203 
    204 	case ADMIN_SHOW_SCHED: {
    205 		caddr_t p = NULL;
    206 		int len;
    207 
    208 		if (sched_dump(&p, &len) != -1) {
    209 			buf = vmalloc(len);
    210 			if (buf != NULL)
    211 				memcpy(buf->v, p, len);
    212 			else
    213 				l_ac_errno = ENOMEM;
    214 			racoon_free(p);
    215 		} else
    216 			l_ac_errno = ENOMEM;
    217 		break;
    218 	}
    219 
    220 	case ADMIN_SHOW_EVT:
    221 		if (com->ac_version == 0) {
    222 			buf = evt_dump();
    223 			l_ac_errno = 0;
    224 		}
    225 		break;
    226 
    227 	case ADMIN_SHOW_SA:
    228 		switch (com->ac_proto) {
    229 		case ADMIN_PROTO_ISAKMP:
    230 			buf = dumpph1();
    231 			if (buf == NULL)
    232 				l_ac_errno = ENOMEM;
    233 			break;
    234 		case ADMIN_PROTO_IPSEC:
    235 		case ADMIN_PROTO_AH:
    236 		case ADMIN_PROTO_ESP: {
    237 			u_int p;
    238 			p = admin2pfkey_proto(com->ac_proto);
    239 			if (p != -1) {
    240 				buf = pfkey_dump_sadb(p);
    241 				if (buf == NULL)
    242 					l_ac_errno = ENOMEM;
    243 			} else
    244 				l_ac_errno = EINVAL;
    245 			break;
    246 		}
    247 		case ADMIN_PROTO_INTERNAL:
    248 		default:
    249 			l_ac_errno = ENOTSUP;
    250 			break;
    251 		}
    252 		break;
    253 
    254 	case ADMIN_GET_SA_CERT: {
    255 		struct admin_com_indexes *ndx;
    256 		struct sockaddr *src, *dst;
    257 		struct ph1handle *iph1;
    258 
    259 		ndx = (struct admin_com_indexes *) ((caddr_t)com + sizeof(*com));
    260 		src = (struct sockaddr *) &ndx->src;
    261 		dst = (struct sockaddr *) &ndx->dst;
    262 
    263 		if (com->ac_proto != ADMIN_PROTO_ISAKMP) {
    264 			l_ac_errno = ENOTSUP;
    265 			break;
    266 		}
    267 
    268 		iph1 = getph1byaddr(src, dst, 0);
    269 		if (iph1 == NULL) {
    270 			l_ac_errno = ENOENT;
    271 			break;
    272 		}
    273 
    274 		if (iph1->cert_p != NULL) {
    275 			vchar_t tmp;
    276 			tmp.v = iph1->cert_p->v + 1;
    277 			tmp.l = iph1->cert_p->l - 1;
    278 			buf = vdup(&tmp);
    279 		}
    280 		break;
    281 	}
    282 
    283 	case ADMIN_FLUSH_SA:
    284 		switch (com->ac_proto) {
    285 		case ADMIN_PROTO_ISAKMP:
    286 			flushph1();
    287 			break;
    288 		case ADMIN_PROTO_IPSEC:
    289 		case ADMIN_PROTO_AH:
    290 		case ADMIN_PROTO_ESP:
    291 			pfkey_flush_sadb(com->ac_proto);
    292 			break;
    293 		case ADMIN_PROTO_INTERNAL:
    294 			/*XXX flushph2();*/
    295 		default:
    296 			l_ac_errno = ENOTSUP;
    297 			break;
    298 		}
    299 		break;
    300 
    301 	case ADMIN_DELETE_SA: {
    302 		char *loc, *rem;
    303 		struct ph1selector sel;
    304 
    305 		memset(&sel, 0, sizeof(sel));
    306 		sel.local = (struct sockaddr *)
    307 			&((struct admin_com_indexes *)
    308 			    ((caddr_t)com + sizeof(*com)))->src;
    309 		sel.remote = (struct sockaddr *)
    310 			&((struct admin_com_indexes *)
    311 			    ((caddr_t)com + sizeof(*com)))->dst;
    312 
    313 		loc = racoon_strdup(saddr2str(sel.local));
    314 		rem = racoon_strdup(saddr2str(sel.remote));
    315 		STRDUP_FATAL(loc);
    316 		STRDUP_FATAL(rem);
    317 
    318 		plog(LLV_INFO, LOCATION, NULL,
    319 		     "admin delete-sa %s %s\n", loc, rem);
    320 		enumph1(&sel, admin_ph1_delete_sa, NULL);
    321 		remcontacted(sel.remote);
    322 
    323 		racoon_free(loc);
    324 		racoon_free(rem);
    325 		break;
    326 	}
    327 
    328 #ifdef ENABLE_HYBRID
    329 	case ADMIN_LOGOUT_USER: {
    330 		struct ph1handle *iph1;
    331 		char user[LOGINLEN+1];
    332 		int found = 0, len = com->ac_len - sizeof(*com);
    333 
    334 		if (len > LOGINLEN) {
    335 			plog(LLV_ERROR, LOCATION, NULL,
    336 			    "malformed message (login too long)\n");
    337 			break;
    338 		}
    339 
    340 		memcpy(user, (char *)(com + 1), len);
    341 		user[len] = 0;
    342 
    343 		found = purgeph1bylogin(user);
    344 		plog(LLV_INFO, LOCATION, NULL,
    345 		    "deleted %d SA for user \"%s\"\n", found, user);
    346 
    347 		break;
    348 	}
    349 #endif
    350 
    351 	case ADMIN_DELETE_ALL_SA_DST: {
    352 		struct ph1handle *iph1;
    353 		struct sockaddr *dst;
    354 		char *loc, *rem;
    355 
    356 		dst = (struct sockaddr *)
    357 			&((struct admin_com_indexes *)
    358 			    ((caddr_t)com + sizeof(*com)))->dst;
    359 
    360 		rem = racoon_strdup(saddrwop2str(dst));
    361 		STRDUP_FATAL(rem);
    362 
    363 		plog(LLV_INFO, LOCATION, NULL,
    364 		    "Flushing all SAs for peer %s\n", rem);
    365 
    366 		while ((iph1 = getph1bydstaddr(dst)) != NULL) {
    367 			loc = racoon_strdup(saddrwop2str(iph1->local));
    368 			STRDUP_FATAL(loc);
    369 
    370 			if (iph1->status >= PHASE1ST_ESTABLISHED)
    371 				isakmp_info_send_d1(iph1);
    372 			purge_remote(iph1);
    373 
    374 			racoon_free(loc);
    375 		}
    376 
    377 		racoon_free(rem);
    378 		break;
    379 	}
    380 
    381 	case ADMIN_ESTABLISH_SA_PSK: {
    382 		struct admin_com_psk *acp;
    383 		char *data;
    384 
    385 		acp = (struct admin_com_psk *)
    386 		    ((char *)com + sizeof(*com) +
    387 		    sizeof(struct admin_com_indexes));
    388 
    389 		idtype = acp->id_type;
    390 
    391 		if ((id = vmalloc(acp->id_len)) == NULL) {
    392 			plog(LLV_ERROR, LOCATION, NULL,
    393 			    "cannot allocate memory: %s\n",
    394 			    strerror(errno));
    395 			break;
    396 		}
    397 		data = (char *)(acp + 1);
    398 		memcpy(id->v, data, id->l);
    399 
    400 		if ((key = vmalloc(acp->key_len)) == NULL) {
    401 			plog(LLV_ERROR, LOCATION, NULL,
    402 			    "cannot allocate memory: %s\n",
    403 			    strerror(errno));
    404 			vfree(id);
    405 			id = NULL;
    406 			break;
    407 		}
    408 		data = (char *)(data + acp->id_len);
    409 		memcpy(key->v, data, key->l);
    410 	}
    411 	/* FALLTHROUGH */
    412 	case ADMIN_ESTABLISH_SA: {
    413 		struct admin_com_indexes *ndx;
    414 		struct sockaddr *dst;
    415 		struct sockaddr *src;
    416 		char *name = NULL;
    417 
    418 		ndx = (struct admin_com_indexes *) ((caddr_t)com + sizeof(*com));
    419 		src = (struct sockaddr *) &ndx->src;
    420 		dst = (struct sockaddr *) &ndx->dst;
    421 
    422 		if (com->ac_cmd == ADMIN_ESTABLISH_SA &&
    423 		    com->ac_len > sizeof(*com) + sizeof(*ndx))
    424 			name = (char *) ((caddr_t) ndx + sizeof(*ndx));
    425 
    426 		switch (com->ac_proto) {
    427 		case ADMIN_PROTO_ISAKMP: {
    428 			struct ph1handle *ph1;
    429 			struct remoteconf *rmconf;
    430 			u_int16_t port;
    431 
    432 			l_ac_errno = -1;
    433 
    434 			/* connected already? */
    435 			ph1 = getph1byaddr(src, dst, 0);
    436 			if (ph1 != NULL) {
    437 				event_list = &ph1->evt_listeners;
    438 				if (ph1->status == PHASE1ST_ESTABLISHED)
    439 					l_ac_errno = EEXIST;
    440 				else
    441 					l_ac_errno = 0;
    442 				break;
    443 			}
    444 
    445 			/* search appropreate configuration */
    446 			if (name == NULL)
    447 				rmconf = getrmconf(dst, 0);
    448 			else
    449 				rmconf = getrmconf_by_name(name);
    450 			if (rmconf == NULL) {
    451 				plog(LLV_ERROR, LOCATION, NULL,
    452 					"no configuration found "
    453 					"for %s\n", saddrwop2str(dst));
    454 				break;
    455 			}
    456 
    457 #ifdef ENABLE_HYBRID
    458 			/* XXX This overwrites rmconf information globally. */
    459 			/* Set the id and key */
    460 			if (id && key) {
    461 				if (xauth_rmconf_used(&rmconf->xauth) == -1)
    462 					break;
    463 
    464 				if (rmconf->xauth->login != NULL) {
    465 					vfree(rmconf->xauth->login);
    466 					rmconf->xauth->login = NULL;
    467 				}
    468 				if (rmconf->xauth->pass != NULL) {
    469 					vfree(rmconf->xauth->pass);
    470 					rmconf->xauth->pass = NULL;
    471 				}
    472 
    473 				rmconf->xauth->login = id;
    474 				rmconf->xauth->pass = key;
    475 			}
    476 #endif
    477 
    478 			plog(LLV_INFO, LOCATION, NULL,
    479 				"accept a request to establish IKE-SA: "
    480 				"%s\n", saddrwop2str(dst));
    481 
    482 			/* begin ident mode */
    483 			ph1 = isakmp_ph1begin_i(rmconf, dst, src);
    484 			if (ph1 == NULL)
    485 				break;
    486 
    487 			event_list = &ph1->evt_listeners;
    488 			l_ac_errno = 0;
    489 			break;
    490 		}
    491 		case ADMIN_PROTO_AH:
    492 		case ADMIN_PROTO_ESP: {
    493 			struct ph2handle *iph2;
    494 			struct secpolicy *sp_out = NULL, *sp_in = NULL;
    495 			struct policyindex spidx;
    496 
    497 			l_ac_errno = -1;
    498 
    499 			/* got outbound policy */
    500 			memset(&spidx, 0, sizeof(spidx));
    501 			spidx.dir = IPSEC_DIR_OUTBOUND;
    502 			memcpy(&spidx.src, src, sizeof(spidx.src));
    503 			memcpy(&spidx.dst, dst, sizeof(spidx.dst));
    504 			spidx.prefs = ndx->prefs;
    505 			spidx.prefd = ndx->prefd;
    506 			spidx.ul_proto = ndx->ul_proto;
    507 
    508 			sp_out = getsp_r(&spidx);
    509 			if (sp_out) {
    510 				plog(LLV_DEBUG, LOCATION, NULL,
    511 					"suitable outbound SP found: %s.\n",
    512 					spidx2str(&sp_out->spidx));
    513 			} else {
    514 				l_ac_errno = ENOENT;
    515 				plog(LLV_NOTIFY, LOCATION, NULL,
    516 					"no outbound policy found: %s\n",
    517 					spidx2str(&spidx));
    518 				break;
    519 			}
    520 
    521 			iph2 = getph2byid(src, dst, sp_out->id);
    522 			if (iph2 != NULL) {
    523 				event_list = &iph2->evt_listeners;
    524 				if (iph2->status == PHASE2ST_ESTABLISHED)
    525 					l_ac_errno = EEXIST;
    526 				else
    527 					l_ac_errno = 0;
    528 				break;
    529 			}
    530 
    531 			/* get inbound policy */
    532 			memset(&spidx, 0, sizeof(spidx));
    533 			spidx.dir = IPSEC_DIR_INBOUND;
    534 			memcpy(&spidx.src, dst, sizeof(spidx.src));
    535 			memcpy(&spidx.dst, src, sizeof(spidx.dst));
    536 			spidx.prefs = ndx->prefd;
    537 			spidx.prefd = ndx->prefs;
    538 			spidx.ul_proto = ndx->ul_proto;
    539 
    540 			sp_in = getsp_r(&spidx);
    541 			if (sp_in) {
    542 				plog(LLV_DEBUG, LOCATION, NULL,
    543 					"suitable inbound SP found: %s.\n",
    544 					spidx2str(&sp_in->spidx));
    545 			} else {
    546 				l_ac_errno = ENOENT;
    547 				plog(LLV_NOTIFY, LOCATION, NULL,
    548 					"no inbound policy found: %s\n",
    549 				spidx2str(&spidx));
    550 				break;
    551 			}
    552 
    553 			/* allocate a phase 2 */
    554 			iph2 = newph2();
    555 			if (iph2 == NULL) {
    556 				plog(LLV_ERROR, LOCATION, NULL,
    557 					"failed to allocate phase2 entry.\n");
    558 				break;
    559 			}
    560 			iph2->side = INITIATOR;
    561 			iph2->satype = admin2pfkey_proto(com->ac_proto);
    562 			iph2->spid = sp_out->id;
    563 			iph2->seq = pk_getseq();
    564 			iph2->status = PHASE2ST_STATUS2;
    565 
    566 			/* set end addresses of SA */
    567 			iph2->sa_dst = dupsaddr(dst);
    568 			iph2->sa_src = dupsaddr(src);
    569 			iph2->dst = dupsaddr(dst);
    570 			iph2->src = dupsaddr(src);
    571 			if (iph2->sa_src == NULL || iph2->sa_dst == NULL ||
    572 			    iph2->dst == NULL || iph2->src == NULL) {
    573 				delph2(iph2);
    574 				break;
    575 			}
    576 			set_port(iph2->dst, 0);
    577 			set_port(iph2->src, 0);
    578 
    579 			if (isakmp_get_sainfo(iph2, sp_out, sp_in) < 0) {
    580 				delph2(iph2);
    581 				break;
    582 			}
    583 
    584 			insph2(iph2);
    585 			if (isakmp_post_acquire(iph2, NULL, FALSE) < 0) {
    586 				remph2(iph2);
    587 				delph2(iph2);
    588 				break;
    589 			}
    590 
    591 			event_list = &iph2->evt_listeners;
    592 			l_ac_errno = 0;
    593 			break;
    594 		}
    595 		default:
    596 			/* ignore */
    597 			l_ac_errno = ENOTSUP;
    598 		}
    599 		break;
    600 	}
    601 
    602 	default:
    603 		plog(LLV_ERROR, LOCATION, NULL,
    604 			"invalid command: %d\n", com->ac_cmd);
    605 		l_ac_errno = ENOTSUP;
    606 	}
    607 
    608 	if ((error = admin_reply(so2, com, l_ac_errno, buf)) != 0)
    609 		goto out;
    610 
    611 	/* start pushing events if so requested */
    612 	if ((l_ac_errno == 0) &&
    613 	    (com->ac_version >= 1) &&
    614 	    (com->ac_cmd == ADMIN_SHOW_EVT || event_list != NULL))
    615 		error = evt_subscribe(event_list, so2);
    616 out:
    617 	if (buf != NULL)
    618 		vfree(buf);
    619 
    620 	return error;
    621 }
    622 
    623 static int
    624 admin_reply(so, req, l_ac_errno, buf)
    625 	int so, l_ac_errno;
    626 	struct admin_com *req;
    627 	vchar_t *buf;
    628 {
    629 	int tlen;
    630 	struct admin_com *combuf;
    631 	char *retbuf = NULL;
    632 
    633 	if (buf != NULL)
    634 		tlen = sizeof(*combuf) + buf->l;
    635 	else
    636 		tlen = sizeof(*combuf);
    637 
    638 	retbuf = racoon_calloc(1, tlen);
    639 	if (retbuf == NULL) {
    640 		plog(LLV_ERROR, LOCATION, NULL,
    641 			"failed to allocate admin buffer\n");
    642 		return -1;
    643 	}
    644 
    645 	combuf = (struct admin_com *) retbuf;
    646 	combuf->ac_len = (u_int16_t) tlen;
    647 	combuf->ac_cmd = req->ac_cmd & ~ADMIN_FLAG_VERSION;
    648 	if (tlen != (u_int32_t) combuf->ac_len &&
    649 	    l_ac_errno == 0) {
    650 		combuf->ac_len_high = tlen >> 16;
    651 		combuf->ac_cmd |= ADMIN_FLAG_LONG_REPLY;
    652 	} else {
    653 		combuf->ac_errno = l_ac_errno;
    654 	}
    655 	combuf->ac_proto = req->ac_proto;
    656 
    657 	if (buf != NULL)
    658 		memcpy(retbuf + sizeof(*combuf), buf->v, buf->l);
    659 
    660 	tlen = send(so, retbuf, tlen, 0);
    661 	racoon_free(retbuf);
    662 	if (tlen < 0) {
    663 		plog(LLV_ERROR, LOCATION, NULL,
    664 			"failed to send admin command: %s\n",
    665 			strerror(errno));
    666 		return -1;
    667 	}
    668 
    669 	return 0;
    670 }
    671 
    672 /* ADMIN_PROTO -> SADB_SATYPE */
    673 int
    674 admin2pfkey_proto(proto)
    675 	u_int proto;
    676 {
    677 	switch (proto) {
    678 	case ADMIN_PROTO_IPSEC:
    679 		return SADB_SATYPE_UNSPEC;
    680 	case ADMIN_PROTO_AH:
    681 		return SADB_SATYPE_AH;
    682 	case ADMIN_PROTO_ESP:
    683 		return SADB_SATYPE_ESP;
    684 	default:
    685 		plog(LLV_ERROR, LOCATION, NULL,
    686 			"unsupported proto for admin: %d\n", proto);
    687 		return -1;
    688 	}
    689 	/*NOTREACHED*/
    690 }
    691 
    692 int
    693 admin_init()
    694 {
    695 	if (adminsock_path == NULL) {
    696 		lcconf->sock_admin = -1;
    697 		return 0;
    698 	}
    699 
    700 	memset(&sunaddr, 0, sizeof(sunaddr));
    701 	sunaddr.sun_family = AF_UNIX;
    702 	snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
    703 		"%s", adminsock_path);
    704 
    705 	lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0);
    706 	if (lcconf->sock_admin == -1) {
    707 		plog(LLV_ERROR, LOCATION, NULL,
    708 			"socket: %s\n", strerror(errno));
    709 		return -1;
    710 	}
    711 	close_on_exec(lcconf->sock_admin);
    712 
    713 	unlink(sunaddr.sun_path);
    714 	if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr,
    715 			sizeof(sunaddr)) != 0) {
    716 		plog(LLV_ERROR, LOCATION, NULL,
    717 			"bind(sockname:%s): %s\n",
    718 			sunaddr.sun_path, strerror(errno));
    719 		(void)close(lcconf->sock_admin);
    720 		return -1;
    721 	}
    722 
    723 	if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) {
    724 		plog(LLV_ERROR, LOCATION, NULL,
    725 		    "chown(%s, %d, %d): %s\n",
    726 		    sunaddr.sun_path, adminsock_owner,
    727 		    adminsock_group, strerror(errno));
    728 		(void)close(lcconf->sock_admin);
    729 		return -1;
    730 	}
    731 
    732 	if (chmod(sunaddr.sun_path, adminsock_mode) != 0) {
    733 		plog(LLV_ERROR, LOCATION, NULL,
    734 		    "chmod(%s, 0%03o): %s\n",
    735 		    sunaddr.sun_path, adminsock_mode, strerror(errno));
    736 		(void)close(lcconf->sock_admin);
    737 		return -1;
    738 	}
    739 
    740 	if (listen(lcconf->sock_admin, 5) != 0) {
    741 		plog(LLV_ERROR, LOCATION, NULL,
    742 			"listen(sockname:%s): %s\n",
    743 			sunaddr.sun_path, strerror(errno));
    744 		(void)close(lcconf->sock_admin);
    745 		return -1;
    746 	}
    747 
    748 	monitor_fd(lcconf->sock_admin, admin_handler, NULL, 0);
    749 	plog(LLV_DEBUG, LOCATION, NULL,
    750 	     "open %s as racoon management.\n", sunaddr.sun_path);
    751 
    752 	return 0;
    753 }
    754 
    755 int
    756 admin_close()
    757 {
    758 	unmonitor_fd(lcconf->sock_admin);
    759 	close(lcconf->sock_admin);
    760 	return 0;
    761 }
    762 
    763 #endif
    764