1130803Smarcel/*	$NetBSD: admin.c,v 1.37 2010/11/12 10:36:37 tteras Exp $	*/
2130803Smarcel
3130803Smarcel/* Id: admin.c,v 1.25 2006/04/06 14:31:04 manubsd Exp */
4130803Smarcel
5130803Smarcel/*
6130803Smarcel * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7130803Smarcel * All rights reserved.
8130803Smarcel *
9130803Smarcel * Redistribution and use in source and binary forms, with or without
10130803Smarcel * modification, are permitted provided that the following conditions
11130803Smarcel * are met:
12130803Smarcel * 1. Redistributions of source code must retain the above copyright
13130803Smarcel *    notice, this list of conditions and the following disclaimer.
14130803Smarcel * 2. Redistributions in binary form must reproduce the above copyright
15130803Smarcel *    notice, this list of conditions and the following disclaimer in the
16130803Smarcel *    documentation and/or other materials provided with the distribution.
17130803Smarcel * 3. Neither the name of the project nor the names of its contributors
18130803Smarcel *    may be used to endorse or promote products derived from this software
19130803Smarcel *    without specific prior written permission.
20130803Smarcel *
21130803Smarcel * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22130803Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23130803Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24130803Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25130803Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26130803Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27130803Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28130803Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29130803Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30130803Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31130803Smarcel * SUCH DAMAGE.
32130803Smarcel */
33130803Smarcel
34130803Smarcel#include "config.h"
35130803Smarcel
36130803Smarcel#include <sys/types.h>
37130803Smarcel#include <sys/param.h>
38130803Smarcel#include <sys/socket.h>
39130803Smarcel#include <sys/signal.h>
40130803Smarcel#include <sys/stat.h>
41130803Smarcel#include <sys/un.h>
42130803Smarcel
43130803Smarcel#include <net/pfkeyv2.h>
44130803Smarcel
45130803Smarcel#include <netinet/in.h>
46130803Smarcel#include PATH_IPSEC_H
47130803Smarcel
48130803Smarcel
49130803Smarcel#include <stdlib.h>
50130803Smarcel#include <stdio.h>
51130803Smarcel#include <string.h>
52130803Smarcel#include <errno.h>
53130803Smarcel#include <netdb.h>
54130803Smarcel#ifdef HAVE_UNISTD_H
55130803Smarcel#include <unistd.h>
56130803Smarcel#endif
57130803Smarcel#ifdef ENABLE_HYBRID
58130803Smarcel#include <resolv.h>
59130803Smarcel#endif
60130803Smarcel
61130803Smarcel#include "var.h"
62130803Smarcel#include "misc.h"
63130803Smarcel#include "vmbuf.h"
64130803Smarcel#include "plog.h"
65130803Smarcel#include "sockmisc.h"
66130803Smarcel#include "debug.h"
67130803Smarcel
68130803Smarcel#include "schedule.h"
69130803Smarcel#include "localconf.h"
70130803Smarcel#include "remoteconf.h"
71130803Smarcel#include "grabmyaddr.h"
72130803Smarcel#include "isakmp_var.h"
73130803Smarcel#include "isakmp.h"
74130803Smarcel#include "oakley.h"
75130803Smarcel#include "handler.h"
76130803Smarcel#include "evt.h"
77130803Smarcel#include "pfkey.h"
78130803Smarcel#include "ipsec_doi.h"
79130803Smarcel#include "policy.h"
80130803Smarcel#include "admin.h"
81130803Smarcel#include "admin_var.h"
82130803Smarcel#include "isakmp_inf.h"
83130803Smarcel#ifdef ENABLE_HYBRID
84130803Smarcel#include "isakmp_cfg.h"
85130803Smarcel#endif
86130803Smarcel#include "session.h"
87130803Smarcel#include "gcmalloc.h"
88130803Smarcel
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(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
156end:
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
170static 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 */
181static int
182admin_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);
616out:
617	if (buf != NULL)
618		vfree(buf);
619
620	return error;
621}
622
623static int
624admin_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 */
673int
674admin2pfkey_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
692int
693admin_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
755int
756admin_close()
757{
758	unmonitor_fd(lcconf->sock_admin);
759	close(lcconf->sock_admin);
760	return 0;
761}
762
763#endif
764