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