xref: /netbsd-src/crypto/dist/ipsec-tools/src/racoon/admin.c (revision 413d532bcc3f62d122e56d92e13ac64825a40baf)
1 /*	$NetBSD: admin.c,v 1.39 2013/06/03 05:49:31 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                         if (sp_out->local && sp_out->remote) {
567                             /* hints available, let's use them */
568                             iph2->sa_dst = dupsaddr(dst);
569                             iph2->sa_src = dupsaddr(src);
570                             iph2->src = dupsaddr((struct sockaddr *)sp_out->local);
571                             iph2->dst = dupsaddr((struct sockaddr *)sp_out->remote);
572                         } else if (sp_out->req && sp_out->req->saidx.mode == IPSEC_MODE_TUNNEL) {
573                             /* Tunnel mode and no hint, use endpoints */
574                             iph2->src = dupsaddr((struct sockaddr *)&sp_out->req->saidx.src);
575                             iph2->dst = dupsaddr((struct sockaddr *)&sp_out->req->saidx.dst);
576                         } else {
577                             /* default, use selectors as fallback */
578                             iph2->sa_dst = dupsaddr(dst);
579                             iph2->sa_src = dupsaddr(src);
580                             iph2->dst = dupsaddr(dst);
581                             iph2->src = dupsaddr(src);
582                         }
583 
584                         if (iph2->dst == NULL || iph2->src == NULL) {
585                             delph2(iph2);
586                             break;
587                         }
588                         set_port(iph2->dst, 0);
589                         set_port(iph2->src, 0);
590 
591 			if (isakmp_get_sainfo(iph2, sp_out, sp_in) < 0) {
592 				delph2(iph2);
593 				break;
594 			}
595 
596 			insph2(iph2);
597 			if (isakmp_post_acquire(iph2, NULL, FALSE) < 0) {
598 				remph2(iph2);
599 				delph2(iph2);
600 				break;
601 			}
602 
603 			event_list = &iph2->evt_listeners;
604 			l_ac_errno = 0;
605 			break;
606 		}
607 		default:
608 			/* ignore */
609 			l_ac_errno = ENOTSUP;
610 		}
611 		break;
612 	}
613 
614 	default:
615 		plog(LLV_ERROR, LOCATION, NULL,
616 			"invalid command: %d\n", com->ac_cmd);
617 		l_ac_errno = ENOTSUP;
618 	}
619 
620 	if ((error = admin_reply(so2, com, l_ac_errno, buf)) != 0)
621 		goto out;
622 
623 	/* start pushing events if so requested */
624 	if ((l_ac_errno == 0) &&
625 	    (com->ac_version >= 1) &&
626 	    (com->ac_cmd == ADMIN_SHOW_EVT || event_list != NULL))
627 		error = evt_subscribe(event_list, so2);
628 out:
629 	if (buf != NULL)
630 		vfree(buf);
631 
632 	return error;
633 }
634 
635 static int
636 admin_reply(so, req, l_ac_errno, buf)
637 	int so, l_ac_errno;
638 	struct admin_com *req;
639 	vchar_t *buf;
640 {
641 	int tlen;
642 	struct admin_com *combuf;
643 	char *retbuf = NULL;
644 
645 	if (buf != NULL)
646 		tlen = sizeof(*combuf) + buf->l;
647 	else
648 		tlen = sizeof(*combuf);
649 
650 	retbuf = racoon_calloc(1, tlen);
651 	if (retbuf == NULL) {
652 		plog(LLV_ERROR, LOCATION, NULL,
653 			"failed to allocate admin buffer\n");
654 		return -1;
655 	}
656 
657 	combuf = (struct admin_com *) retbuf;
658 	combuf->ac_len = (u_int16_t) tlen;
659 	combuf->ac_cmd = req->ac_cmd & ~ADMIN_FLAG_VERSION;
660 	if (tlen != (u_int32_t) combuf->ac_len &&
661 	    l_ac_errno == 0) {
662 		combuf->ac_len_high = tlen >> 16;
663 		combuf->ac_cmd |= ADMIN_FLAG_LONG_REPLY;
664 	} else {
665 		combuf->ac_errno = l_ac_errno;
666 	}
667 	combuf->ac_proto = req->ac_proto;
668 
669 	if (buf != NULL)
670 		memcpy(retbuf + sizeof(*combuf), buf->v, buf->l);
671 
672 	tlen = send(so, retbuf, tlen, 0);
673 	racoon_free(retbuf);
674 	if (tlen < 0) {
675 		plog(LLV_ERROR, LOCATION, NULL,
676 			"failed to send admin command: %s\n",
677 			strerror(errno));
678 		return -1;
679 	}
680 
681 	return 0;
682 }
683 
684 /* ADMIN_PROTO -> SADB_SATYPE */
685 int
686 admin2pfkey_proto(proto)
687 	u_int proto;
688 {
689 	switch (proto) {
690 	case ADMIN_PROTO_IPSEC:
691 		return SADB_SATYPE_UNSPEC;
692 	case ADMIN_PROTO_AH:
693 		return SADB_SATYPE_AH;
694 	case ADMIN_PROTO_ESP:
695 		return SADB_SATYPE_ESP;
696 	default:
697 		plog(LLV_ERROR, LOCATION, NULL,
698 			"unsupported proto for admin: %d\n", proto);
699 		return -1;
700 	}
701 	/*NOTREACHED*/
702 }
703 
704 int
705 admin_init()
706 {
707 	if (adminsock_path == NULL) {
708 		lcconf->sock_admin = -1;
709 		return 0;
710 	}
711 
712 	memset(&sunaddr, 0, sizeof(sunaddr));
713 	sunaddr.sun_family = AF_UNIX;
714 	snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
715 		"%s", adminsock_path);
716 
717 	lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0);
718 	if (lcconf->sock_admin == -1) {
719 		plog(LLV_ERROR, LOCATION, NULL,
720 			"socket: %s\n", strerror(errno));
721 		return -1;
722 	}
723 	close_on_exec(lcconf->sock_admin);
724 
725 	unlink(sunaddr.sun_path);
726 	if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr,
727 			sizeof(sunaddr)) != 0) {
728 		plog(LLV_ERROR, LOCATION, NULL,
729 			"bind(sockname:%s): %s\n",
730 			sunaddr.sun_path, strerror(errno));
731 		(void)close(lcconf->sock_admin);
732 		return -1;
733 	}
734 
735 	if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) {
736 		plog(LLV_ERROR, LOCATION, NULL,
737 		    "chown(%s, %d, %d): %s\n",
738 		    sunaddr.sun_path, adminsock_owner,
739 		    adminsock_group, strerror(errno));
740 		(void)close(lcconf->sock_admin);
741 		return -1;
742 	}
743 
744 	if (chmod(sunaddr.sun_path, adminsock_mode) != 0) {
745 		plog(LLV_ERROR, LOCATION, NULL,
746 		    "chmod(%s, 0%03o): %s\n",
747 		    sunaddr.sun_path, adminsock_mode, strerror(errno));
748 		(void)close(lcconf->sock_admin);
749 		return -1;
750 	}
751 
752 	if (listen(lcconf->sock_admin, 5) != 0) {
753 		plog(LLV_ERROR, LOCATION, NULL,
754 			"listen(sockname:%s): %s\n",
755 			sunaddr.sun_path, strerror(errno));
756 		(void)close(lcconf->sock_admin);
757 		return -1;
758 	}
759 
760 	monitor_fd(lcconf->sock_admin, admin_handler, NULL, 0);
761 	plog(LLV_DEBUG, LOCATION, NULL,
762 	     "open %s as racoon management.\n", sunaddr.sun_path);
763 
764 	return 0;
765 }
766 
767 int
768 admin_close()
769 {
770 	unmonitor_fd(lcconf->sock_admin);
771 	close(lcconf->sock_admin);
772 	return 0;
773 }
774 
775 #endif
776