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
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
admin_handler(void * ctx,int fd)100 admin_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 
154 end:
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 
admin_ph1_delete_sa(struct ph1handle * iph1,void * arg)168 static 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  */
179 static int
admin_process(so2,combuf)180 admin_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);
624 out:
625 	if (buf != NULL)
626 		vfree(buf);
627 
628 	return error;
629 }
630 
631 static int
admin_reply(so,req,l_ac_errno,buf)632 admin_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 */
681 int
admin2pfkey_proto(proto)682 admin2pfkey_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 
700 int
admin_init()701 admin_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 
763 int
admin_close()764 admin_close()
765 {
766 	unmonitor_fd(lcconf->sock_admin);
767 	close(lcconf->sock_admin);
768 	return 0;
769 }
770 
771 #endif
772