admin.c revision 1.33
1/*	$NetBSD: admin.c,v 1.33 2010/09/22 13:37:35 vanhu 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(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		struct ph1handle *iph1;
303		struct ph1selector sel;
304		char *loc, *rem;
305
306		memset(&sel, 0, sizeof(sel));
307		sel.local = (struct sockaddr *)
308			&((struct admin_com_indexes *)
309			    ((caddr_t)com + sizeof(*com)))->src;
310		sel.remote = (struct sockaddr *)
311			&((struct admin_com_indexes *)
312			    ((caddr_t)com + sizeof(*com)))->dst;
313
314		loc = racoon_strdup(saddr2str(sel.local));
315		rem = racoon_strdup(saddr2str(sel.remote));
316		STRDUP_FATAL(loc);
317		STRDUP_FATAL(rem);
318
319		plog(LLV_INFO, LOCATION, NULL,
320		     "admin delete-sa %s %s\n", loc, rem);
321		enumph1(&sel, admin_ph1_delete_sa, NULL);
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->dst = dupsaddr(dst);
568			iph2->src = dupsaddr(src);
569			if (iph2->dst == NULL || iph2->src == NULL) {
570				delph2(iph2);
571				break;
572			}
573
574			if (isakmp_get_sainfo(iph2, sp_out, sp_in) < 0) {
575				delph2(iph2);
576				break;
577			}
578
579			insph2(iph2);
580			if (isakmp_post_acquire(iph2, NULL) < 0) {
581				remph2(iph2);
582				delph2(iph2);
583				break;
584			}
585
586			event_list = &iph2->evt_listeners;
587			l_ac_errno = 0;
588			break;
589		}
590		default:
591			/* ignore */
592			l_ac_errno = ENOTSUP;
593		}
594		break;
595	}
596
597	default:
598		plog(LLV_ERROR, LOCATION, NULL,
599			"invalid command: %d\n", com->ac_cmd);
600		l_ac_errno = ENOTSUP;
601	}
602
603	if ((error = admin_reply(so2, com, l_ac_errno, buf)) != 0)
604		goto out;
605
606	/* start pushing events if so requested */
607	if ((l_ac_errno == 0) &&
608	    (com->ac_version >= 1) &&
609	    (com->ac_cmd == ADMIN_SHOW_EVT || event_list != NULL))
610		error = evt_subscribe(event_list, so2);
611out:
612	if (buf != NULL)
613		vfree(buf);
614
615	return error;
616}
617
618static int
619admin_reply(so, req, l_ac_errno, buf)
620	int so, l_ac_errno;
621	struct admin_com *req;
622	vchar_t *buf;
623{
624	int tlen;
625	struct admin_com *combuf;
626	char *retbuf = NULL;
627
628	if (buf != NULL)
629		tlen = sizeof(*combuf) + buf->l;
630	else
631		tlen = sizeof(*combuf);
632
633	retbuf = racoon_calloc(1, tlen);
634	if (retbuf == NULL) {
635		plog(LLV_ERROR, LOCATION, NULL,
636			"failed to allocate admin buffer\n");
637		return -1;
638	}
639
640	combuf = (struct admin_com *) retbuf;
641	combuf->ac_len = tlen;
642	combuf->ac_cmd = req->ac_cmd & ~ADMIN_FLAG_VERSION;
643	combuf->ac_errno = l_ac_errno;
644	combuf->ac_proto = req->ac_proto;
645
646	if (buf != NULL)
647		memcpy(retbuf + sizeof(*combuf), buf->v, buf->l);
648
649	tlen = send(so, retbuf, tlen, 0);
650	racoon_free(retbuf);
651	if (tlen < 0) {
652		plog(LLV_ERROR, LOCATION, NULL,
653			"failed to send admin command: %s\n",
654			strerror(errno));
655		return -1;
656	}
657
658	return 0;
659}
660
661/* ADMIN_PROTO -> SADB_SATYPE */
662int
663admin2pfkey_proto(proto)
664	u_int proto;
665{
666	switch (proto) {
667	case ADMIN_PROTO_IPSEC:
668		return SADB_SATYPE_UNSPEC;
669	case ADMIN_PROTO_AH:
670		return SADB_SATYPE_AH;
671	case ADMIN_PROTO_ESP:
672		return SADB_SATYPE_ESP;
673	default:
674		plog(LLV_ERROR, LOCATION, NULL,
675			"unsupported proto for admin: %d\n", proto);
676		return -1;
677	}
678	/*NOTREACHED*/
679}
680
681int
682admin_init()
683{
684	if (adminsock_path == NULL) {
685		lcconf->sock_admin = -1;
686		return 0;
687	}
688
689	memset(&sunaddr, 0, sizeof(sunaddr));
690	sunaddr.sun_family = AF_UNIX;
691	snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
692		"%s", adminsock_path);
693
694	lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0);
695	if (lcconf->sock_admin == -1) {
696		plog(LLV_ERROR, LOCATION, NULL,
697			"socket: %s\n", strerror(errno));
698		return -1;
699	}
700	close_on_exec(lcconf->sock_admin);
701
702	unlink(sunaddr.sun_path);
703	if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr,
704			sizeof(sunaddr)) != 0) {
705		plog(LLV_ERROR, LOCATION, NULL,
706			"bind(sockname:%s): %s\n",
707			sunaddr.sun_path, strerror(errno));
708		(void)close(lcconf->sock_admin);
709		return -1;
710	}
711
712	if (chown(sunaddr.sun_path, adminsock_owner, adminsock_group) != 0) {
713		plog(LLV_ERROR, LOCATION, NULL,
714		    "chown(%s, %d, %d): %s\n",
715		    sunaddr.sun_path, adminsock_owner,
716		    adminsock_group, strerror(errno));
717		(void)close(lcconf->sock_admin);
718		return -1;
719	}
720
721	if (chmod(sunaddr.sun_path, adminsock_mode) != 0) {
722		plog(LLV_ERROR, LOCATION, NULL,
723		    "chmod(%s, 0%03o): %s\n",
724		    sunaddr.sun_path, adminsock_mode, strerror(errno));
725		(void)close(lcconf->sock_admin);
726		return -1;
727	}
728
729	if (listen(lcconf->sock_admin, 5) != 0) {
730		plog(LLV_ERROR, LOCATION, NULL,
731			"listen(sockname:%s): %s\n",
732			sunaddr.sun_path, strerror(errno));
733		(void)close(lcconf->sock_admin);
734		return -1;
735	}
736
737	monitor_fd(lcconf->sock_admin, admin_handler, NULL);
738	plog(LLV_DEBUG, LOCATION, NULL,
739	     "open %s as racoon management.\n", sunaddr.sun_path);
740
741	return 0;
742}
743
744int
745admin_close()
746{
747	unmonitor_fd(lcconf->sock_admin);
748	close(lcconf->sock_admin);
749	return 0;
750}
751
752#endif
753