xref: /netbsd-src/crypto/dist/ipsec-tools/src/racoon/admin.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
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