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