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