1/*	$NetBSD: racoonctl.c,v 1.7.6.2 2009/04/20 13:32:57 tteras Exp $	*/
2
3/*	Id: racoonctl.c,v 1.11 2006/04/06 17:06:25 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/un.h>
40
41#include <netinet/in.h>
42#include <arpa/inet.h>
43#include <net/pfkeyv2.h>
44
45#include <stdlib.h>
46#include <stdio.h>
47#include <string.h>
48#include <errno.h>
49#if TIME_WITH_SYS_TIME
50# include <sys/time.h>
51# include <time.h>
52#else
53# if HAVE_SYS_TIME_H
54#  include <sys/time.h>
55# else
56#  include <time.h>
57# endif
58#endif
59#include <netdb.h>
60#ifdef HAVE_UNISTD_H
61#include <unistd.h>
62#endif
63#include <err.h>
64#include <sys/ioctl.h>
65#include <resolv.h>
66
67#include "var.h"
68#include "vmbuf.h"
69#include "misc.h"
70#include "gcmalloc.h"
71
72#include "racoonctl.h"
73#include "admin.h"
74#include "schedule.h"
75#include "handler.h"
76#include "sockmisc.h"
77#include "vmbuf.h"
78#include "plog.h"
79#include "isakmp_var.h"
80#include "isakmp.h"
81#include "isakmp_xauth.h"
82#include "isakmp_cfg.h"
83#include "isakmp_unity.h"
84#include "ipsec_doi.h"
85#include "evt.h"
86
87char *adminsock_path = ADMINSOCK_PATH;
88
89static void usage __P((void));
90static vchar_t *get_combuf __P((int, char **));
91static int handle_recv __P((vchar_t *));
92static vchar_t *f_reload __P((int, char **));
93static vchar_t *f_getsched __P((int, char **));
94static vchar_t *f_getsa __P((int, char **));
95static vchar_t *f_flushsa __P((int, char **));
96static vchar_t *f_deletesa __P((int, char **));
97static vchar_t *f_exchangesa __P((int, char **));
98static vchar_t *f_vpnc __P((int, char **));
99static vchar_t *f_vpnd __P((int, char **));
100static vchar_t *f_getevt __P((int, char **));
101#ifdef ENABLE_HYBRID
102static vchar_t *f_logoutusr __P((int, char **));
103#endif
104
105struct cmd_tag {
106	vchar_t *(*func) __P((int, char **));
107	int cmd;
108	char *str;
109} cmdtab[] = {
110	{ f_reload,	ADMIN_RELOAD_CONF,	"reload-config" },
111	{ f_reload,	ADMIN_RELOAD_CONF,	"rc" },
112	{ f_getsched,	ADMIN_SHOW_SCHED,	"show-schedule" },
113	{ f_getsched,	ADMIN_SHOW_SCHED,	"sc" },
114	{ f_getsa,	ADMIN_SHOW_SA,		"show-sa" },
115	{ f_getsa,	ADMIN_SHOW_SA,		"ss" },
116	{ f_flushsa,	ADMIN_FLUSH_SA,		"flush-sa" },
117	{ f_flushsa,	ADMIN_FLUSH_SA,		"fs" },
118	{ f_deletesa,	ADMIN_DELETE_SA,	"delete-sa" },
119	{ f_deletesa,	ADMIN_DELETE_SA,	"ds" },
120	{ f_exchangesa,	ADMIN_ESTABLISH_SA,	"establish-sa" },
121	{ f_exchangesa,	ADMIN_ESTABLISH_SA,	"es" },
122	{ f_vpnc,	ADMIN_ESTABLISH_SA,	"vpn-connect" },
123	{ f_vpnc,	ADMIN_ESTABLISH_SA,	"vc" },
124	{ f_vpnd,	ADMIN_DELETE_ALL_SA_DST,"vpn-disconnect" },
125	{ f_vpnd,	ADMIN_DELETE_ALL_SA_DST,"vd" },
126	{ f_getevt,	ADMIN_SHOW_EVT,		"show-event" },
127	{ f_getevt,	ADMIN_SHOW_EVT,		"se" },
128#ifdef ENABLE_HYBRID
129	{ f_logoutusr,	ADMIN_LOGOUT_USER,	"logout-user" },
130	{ f_logoutusr,	ADMIN_LOGOUT_USER,	"lu" },
131#endif
132	{ NULL, 0, NULL },
133};
134
135struct evtmsg {
136	int type;
137	char *msg;
138	enum { UNSPEC, ERROR, INFO } level;
139} evtmsg[] = {
140	{ EVTT_PHASE1_UP, "Phase 1 established", INFO },
141	{ EVTT_PHASE1_DOWN, "Phase 1 deleted", INFO },
142	{ EVTT_XAUTH_SUCCESS, "Xauth exchange passed", INFO },
143	{ EVTT_ISAKMP_CFG_DONE, "ISAKMP mode config done", INFO },
144	{ EVTT_PHASE2_UP, "Phase 2 established", INFO },
145	{ EVTT_PHASE2_DOWN, "Phase 2 deleted", INFO },
146	{ EVTT_DPD_TIMEOUT, "Peer not reachable anymore", ERROR },
147	{ EVTT_PEER_NO_RESPONSE, "Peer not responding", ERROR },
148	{ EVTT_PEER_DELETE, "Peer terminated security association", ERROR },
149	{ EVTT_RACOON_QUIT, "Raccon terminated", ERROR },
150	{ EVTT_OVERFLOW, "Event queue overflow", ERROR },
151	{ EVTT_XAUTH_FAILED, "Xauth exchange failed", ERROR },
152	{ EVTT_PEERPH1AUTH_FAILED, "Peer failed phase 1 authentication "
153	    "(certificate problem?)", ERROR },
154	{ EVTT_PEERPH1_NOPROP, "Peer failed phase 1 initiation "
155	    "(proposal problem?)", ERROR },
156	{ 0, NULL, UNSPEC },
157	{ EVTT_NO_ISAKMP_CFG, "No need for ISAKMP mode config ", INFO },
158};
159
160static int get_proto __P((char *));
161static vchar_t *get_index __P((int, char **));
162static int get_family __P((char *));
163static vchar_t *get_comindexes __P((int, int, char **));
164static int get_comindex __P((char *, char **, char **, char **));
165static int get_ulproto __P((char *));
166
167struct proto_tag {
168	int proto;
169	char *str;
170} prototab[] = {
171	{ ADMIN_PROTO_ISAKMP,	"isakmp" },
172	{ ADMIN_PROTO_IPSEC,	"ipsec" },
173	{ ADMIN_PROTO_AH,	"ah" },
174	{ ADMIN_PROTO_ESP,	"esp" },
175	{ ADMIN_PROTO_INTERNAL,	"internal" },
176	{ 0, NULL },
177};
178
179struct ulproto_tag {
180	int ul_proto;
181	char *str;
182} ulprototab[] = {
183	{ 0,		"any" },
184	{ IPPROTO_ICMP,	"icmp" },
185	{ IPPROTO_TCP,	"tcp" },
186	{ IPPROTO_UDP,	"udp" },
187	{ 0, NULL },
188};
189
190int so;
191
192static char _addr1_[NI_MAXHOST], _addr2_[NI_MAXHOST];
193
194char *pname;
195int long_format = 0;
196
197#define EVTF_NONE		0x0000	/* Ignore any events */
198#define EVTF_LOOP		0x0001	/* Loop awaiting for new events */
199#define EVTF_CFG_STOP		0x0002	/* Stop after ISAKMP mode config */
200#define EVTF_CFG		0x0004	/* Print ISAKMP mode config info */
201#define EVTF_ALL		0x0008	/* Print any events */
202#define EVTF_PURGE		0x0010	/* Print all available events */
203#define EVTF_PH1DOWN_STOP	0x0020	/* Stop when phase 1 SA gets down */
204#define EVTF_PH1DOWN		0x0040	/* Print that phase 1 SA got down */
205#define EVTF_ERR		0x0080	/* Print any error */
206#define EVTF_ERR_STOP		0x0100	/* Stop on any error */
207
208int evt_filter = EVTF_NONE;
209time_t evt_start;
210
211void dump_isakmp_sa __P((char *, int));
212void dump_internal __P((char *, int));
213char *pindex_isakmp __P((isakmp_index *));
214void print_schedule __P((caddr_t, int));
215void print_evt __P((caddr_t, int));
216void print_cfg __P((caddr_t, int));
217void print_err __P((caddr_t, int));
218void print_ph1down __P((caddr_t, int));
219void print_ph1up __P((caddr_t, int));
220int evt_poll __P((void));
221char * fixed_addr __P((char *, char *, int));
222
223static void
224usage()
225{
226	printf(
227"Usage:\n"
228"  %s reload-config\n"
229"  %s [-l [-l]] show-sa [protocol]\n"
230"  %s flush-sa [protocol]\n"
231"  %s delete-sa <saopts>\n"
232"  %s establish-sa [-u identity] <saopts>\n"
233"  %s vpn-connect [-u identity] vpn_gateway\n"
234"  %s vpn-disconnect vpn_gateway\n"
235"\n"
236"    <protocol>: \"isakmp\", \"esp\" or \"ah\".\n"
237"        In the case of \"show-sa\" or \"flush-sa\", you can use \"ipsec\".\n"
238"\n"
239"    <saopts>: \"isakmp\" <family> <src> <dst>\n"
240"            : {\"esp\",\"ah\"} <family> <src/prefixlen/port> <dst/prefixlen/port>\n"
241"                              <ul_proto>\n"
242"    <family>: \"inet\" or \"inet6\"\n"
243"    <ul_proto>: \"icmp\", \"tcp\", \"udp\" or \"any\"\n",
244	pname, pname, pname, pname, pname, pname, pname);
245}
246
247/*
248 * Check for proper racoonctl interface
249 */
250#if ((RACOONCTL_INTERFACE_MAJOR != 1) || (RACOONCTL_INTERFACE < 20041230))
251#error	"Incompatible racoonctl interface"
252#endif
253
254int
255main(ac, av)
256	int ac;
257	char **av;
258{
259	vchar_t *combuf;
260	int c;
261
262	pname = *av;
263
264	/*
265	 * Check for proper racoonctl interface
266	 */
267	if ((racoonctl_interface_major != RACOONCTL_INTERFACE_MAJOR) ||
268	    (racoonctl_interface < RACOONCTL_INTERFACE))
269		errx(1, "Incompatible racoonctl interface");
270
271#ifdef __linux__
272	/*
273	 * Disable GNU extensions that will prevent racoonct vc -u login
274	 * from working (GNU getopt(3) does not like options after vc)
275	 */
276	setenv("POSIXLY_CORRECT", "1", 0);
277#endif
278	while ((c = getopt(ac, av, "lds:")) != -1) {
279		switch(c) {
280		case 'l':
281			long_format++;
282			break;
283
284		case 'd':
285			loglevel++;
286			break;
287
288		case 's':
289			adminsock_path = optarg;
290			break;
291
292		default:
293			usage();
294			exit(0);
295		}
296	}
297
298	ac -= optind;
299	av += optind;
300
301	combuf = get_combuf(ac, av);
302	if (!combuf)
303		err(1, "kmpstat");
304
305	if (loglevel)
306		racoon_hexdump(combuf, ((struct admin_com *)combuf)->ac_len);
307
308	com_init();
309
310	if (com_send(combuf) != 0)
311		goto bad;
312
313	vfree(combuf);
314
315	if (com_recv(&combuf) != 0)
316		goto bad;
317	if (handle_recv(combuf) != 0)
318		goto bad;
319
320	vfree(combuf);
321
322	if (evt_filter != EVTF_NONE)
323		if (evt_poll() != 0)
324			goto bad;
325
326	exit(0);
327
328    bad:
329	exit(1);
330}
331
332int
333evt_poll(void) {
334	struct timeval tv;
335	vchar_t *recvbuf;
336	vchar_t *sendbuf;
337
338	if ((sendbuf = f_getevt(0, NULL)) == NULL)
339		errx(1, "Cannot make combuf");
340
341
342	while (evt_filter & (EVTF_LOOP|EVTF_PURGE)) {
343		/* handle_recv closes the socket time, so open it each time */
344		com_init();
345
346		if (com_send(sendbuf) != 0)
347			errx(1, "Cannot send combuf");
348
349		if (com_recv(&recvbuf) == 0) {
350			handle_recv(recvbuf);
351			vfree(recvbuf);
352		}
353
354		tv.tv_sec = 0;
355		tv.tv_usec = 10;
356		(void)select(0, NULL, NULL, NULL, &tv);
357	}
358
359	vfree(sendbuf);
360	return 0;
361}
362
363/* %%% */
364/*
365 * return command buffer.
366 */
367static vchar_t *
368get_combuf(ac, av)
369	int ac;
370	char **av;
371{
372	struct cmd_tag *cp;
373
374	if (ac == 0) {
375		usage();
376		exit(0);
377	}
378
379	/* checking the string of command. */
380	for (cp = &cmdtab[0]; cp->str; cp++) {
381		if (strcmp(*av, cp->str) == 0) {
382			break;
383		}
384	}
385	if (!cp->str) {
386		printf("Invalid command [%s]\n", *av);
387		errno = EINVAL;
388		return NULL;
389	}
390
391	ac--;
392	av++;
393	return (cp->func)(ac, av);
394}
395
396static vchar_t *
397f_reload(ac, av)
398	int ac;
399	char **av;
400{
401	vchar_t *buf;
402	struct admin_com *head;
403
404	buf = vmalloc(sizeof(*head));
405	if (buf == NULL)
406		errx(1, "not enough core");
407
408	head = (struct admin_com *)buf->v;
409	head->ac_len = buf->l;
410	head->ac_cmd = ADMIN_RELOAD_CONF;
411	head->ac_errno = 0;
412	head->ac_proto = 0;
413
414	return buf;
415}
416
417static vchar_t *
418f_getevt(ac, av)
419	int ac;
420	char **av;
421{
422	vchar_t *buf;
423	struct admin_com *head;
424
425	/*
426	 * There are 3 ways of getting here
427	 * 1) racoonctl vc => evt_filter = (EVTF_LOOP|EVTF_CFG| ... )
428	 * 2) racoonctl es => evt_filter = EVTF_NONE
429	 * 3) racoonctl es -l => evt_filter = EVTF_LOOP
430	 * Catch the second case: show-event is here to purge all
431	 */
432	if (evt_filter == EVTF_NONE)
433		evt_filter = (EVTF_ALL|EVTF_PURGE);
434
435	if ((ac >= 1) && (strcmp(av[0], "-l") == 0))
436		evt_filter |= EVTF_LOOP;
437
438	if (ac >= 2)
439		errx(1, "too many arguments");
440
441	buf = vmalloc(sizeof(*head));
442	if (buf == NULL)
443		errx(1, "not enough core");
444
445	head = (struct admin_com *)buf->v;
446	head->ac_len = buf->l;
447	head->ac_cmd = ADMIN_SHOW_EVT;
448	head->ac_errno = 0;
449	head->ac_proto = 0;
450
451	return buf;
452}
453
454static vchar_t *
455f_getsched(ac, av)
456	int ac;
457	char **av;
458{
459	vchar_t *buf;
460	struct admin_com *head;
461
462	buf = vmalloc(sizeof(*head));
463	if (buf == NULL)
464		errx(1, "not enough core");
465
466	head = (struct admin_com *)buf->v;
467	head->ac_len = buf->l;
468	head->ac_cmd = ADMIN_SHOW_SCHED;
469	head->ac_errno = 0;
470	head->ac_proto = 0;
471
472	return buf;
473}
474
475static vchar_t *
476f_getsa(ac, av)
477	int ac;
478	char **av;
479{
480	vchar_t *buf;
481	struct admin_com *head;
482	int proto;
483
484	/* need protocol */
485	if (ac != 1)
486		errx(1, "insufficient arguments");
487	proto = get_proto(*av);
488	if (proto == -1)
489		errx(1, "unknown protocol %s", *av);
490
491	buf = vmalloc(sizeof(*head));
492	if (buf == NULL)
493		errx(1, "not enough core");
494
495	head = (struct admin_com *)buf->v;
496	head->ac_len = buf->l;
497	head->ac_cmd = ADMIN_SHOW_SA;
498	head->ac_errno = 0;
499	head->ac_proto = proto;
500
501	return buf;
502}
503
504static vchar_t *
505f_flushsa(ac, av)
506	int ac;
507	char **av;
508{
509	vchar_t *buf;
510	struct admin_com *head;
511	int proto;
512
513	/* need protocol */
514	if (ac != 1)
515		errx(1, "insufficient arguments");
516	proto = get_proto(*av);
517	if (proto == -1)
518		errx(1, "unknown protocol %s", *av);
519
520	buf = vmalloc(sizeof(*head));
521	if (buf == NULL)
522		errx(1, "not enough core");
523
524	head = (struct admin_com *)buf->v;
525	head->ac_len = buf->l;
526	head->ac_cmd = ADMIN_FLUSH_SA;
527	head->ac_errno = 0;
528	head->ac_proto = proto;
529
530	return buf;
531}
532
533static vchar_t *
534f_deletesa(ac, av)
535	int ac;
536	char **av;
537{
538	vchar_t *buf, *index;
539	struct admin_com *head;
540	int proto;
541
542	/* need protocol */
543	if (ac < 1)
544		errx(1, "insufficient arguments");
545	proto = get_proto(*av);
546	if (proto == -1)
547		errx(1, "unknown protocol %s", *av);
548
549	/* get index(es) */
550	av++;
551	ac--;
552	switch (proto) {
553	case ADMIN_PROTO_ISAKMP:
554		index = get_index(ac, av);
555		if (index == NULL)
556			return NULL;
557		break;
558	case ADMIN_PROTO_AH:
559	case ADMIN_PROTO_ESP:
560		index = get_index(ac, av);
561		if (index == NULL)
562			return NULL;
563		break;
564	default:
565		errno = EPROTONOSUPPORT;
566		return NULL;
567	}
568
569	buf = vmalloc(sizeof(*head) + index->l);
570	if (buf == NULL)
571		goto out;
572
573	head = (struct admin_com *)buf->v;
574	head->ac_len = buf->l + index->l;
575	head->ac_cmd = ADMIN_DELETE_SA;
576	head->ac_errno = 0;
577	head->ac_proto = proto;
578
579	memcpy(buf->v+sizeof(*head), index->v, index->l);
580
581out:
582	if (index != NULL)
583		vfree(index);
584
585	return buf;
586}
587
588static vchar_t *
589f_deleteallsadst(ac, av)
590	int ac;
591	char **av;
592{
593	vchar_t *buf, *index;
594	struct admin_com *head;
595	int proto;
596
597	/* need protocol */
598	if (ac < 1)
599		errx(1, "insufficient arguments");
600	proto = get_proto(*av);
601	if (proto == -1)
602		errx(1, "unknown protocol %s", *av);
603
604	/* get index(es) */
605	av++;
606	ac--;
607	switch (proto) {
608	case ADMIN_PROTO_ISAKMP:
609		index = get_index(ac, av);
610		if (index == NULL)
611			return NULL;
612		break;
613	case ADMIN_PROTO_AH:
614	case ADMIN_PROTO_ESP:
615		index = get_index(ac, av);
616		if (index == NULL)
617			return NULL;
618		break;
619	default:
620		errno = EPROTONOSUPPORT;
621		return NULL;
622	}
623
624	buf = vmalloc(sizeof(*head) + index->l);
625	if (buf == NULL)
626		goto out;
627
628	head = (struct admin_com *)buf->v;
629	head->ac_len = buf->l + index->l;
630	head->ac_cmd = ADMIN_DELETE_ALL_SA_DST;
631	head->ac_errno = 0;
632	head->ac_proto = proto;
633
634	memcpy(buf->v+sizeof(*head), index->v, index->l);
635
636out:
637	if (index != NULL)
638		vfree(index);
639
640	return buf;
641}
642
643static vchar_t *
644f_exchangesa(ac, av)
645	int ac;
646	char **av;
647{
648	vchar_t *buf, *index;
649	struct admin_com *head;
650	int proto;
651	int cmd = ADMIN_ESTABLISH_SA;
652	size_t com_len = 0;
653	char *id = NULL;
654	char *key = NULL;
655	struct admin_com_psk *acp;
656
657	if (ac < 1)
658		errx(1, "insufficient arguments");
659
660	/* Optional -u identity */
661	if (strcmp(av[0], "-u") == 0) {
662		if (ac < 2)
663			errx(1, "-u require an argument");
664
665		id = av[1];
666		if ((key = getpass("Password: ")) == NULL)
667			errx(1, "getpass() failed: %s", strerror(errno));
668
669		com_len += sizeof(*acp) + strlen(id) + 1 + strlen(key) + 1;
670		cmd = ADMIN_ESTABLISH_SA_PSK;
671
672		av += 2;
673		ac -= 2;
674	}
675
676	/* need protocol */
677	if (ac < 1)
678		errx(1, "insufficient arguments");
679	if ((proto = get_proto(*av)) == -1)
680		errx(1, "unknown protocol %s", *av);
681
682	/* get index(es) */
683	av++;
684	ac--;
685	switch (proto) {
686	case ADMIN_PROTO_ISAKMP:
687		index = get_index(ac, av);
688		if (index == NULL)
689			return NULL;
690		break;
691	case ADMIN_PROTO_AH:
692	case ADMIN_PROTO_ESP:
693		index = get_index(ac, av);
694		if (index == NULL)
695			return NULL;
696		break;
697	default:
698		errno = EPROTONOSUPPORT;
699		return NULL;
700	}
701
702	com_len += sizeof(*head) + index->l;
703	if ((buf = vmalloc(com_len)) == NULL)
704		errx(1, "Cannot allocate buffer");
705
706	head = (struct admin_com *)buf->v;
707	head->ac_len = buf->l;
708	head->ac_cmd = cmd;
709	head->ac_errno = 0;
710	head->ac_proto = proto;
711
712	memcpy(buf->v+sizeof(*head), index->v, index->l);
713
714	if (id && key) {
715		char *data;
716		acp = (struct admin_com_psk *)
717		    (buf->v + sizeof(*head) + index->l);
718
719		acp->id_type = IDTYPE_USERFQDN;
720		acp->id_len = strlen(id) + 1;
721		acp->key_len = strlen(key) + 1;
722
723		data = (char *)(acp + 1);
724		strcpy(data, id);
725
726		data = (char *)(data + acp->id_len);
727		strcpy(data, key);
728	}
729
730	vfree(index);
731
732	return buf;
733}
734
735static vchar_t *
736f_vpnc(ac, av)
737	int ac;
738	char **av;
739{
740	char *nav[] = {NULL, NULL, NULL, NULL, NULL, NULL};
741	int nac = 0;
742	char *isakmp = "isakmp";
743	char *inet = "inet";
744	char *srcaddr;
745	struct addrinfo hints, *res;
746	struct sockaddr *src;
747	char *idx;
748
749	if (ac < 1)
750		errx(1, "insufficient arguments");
751
752	evt_filter = (EVTF_LOOP|EVTF_CFG|EVTF_CFG_STOP|EVTF_ERR|EVTF_ERR_STOP);
753	time(&evt_start);
754
755	/* Optional -u identity */
756	if (strcmp(av[0], "-u") == 0) {
757		if (ac < 2)
758			errx(1, "-u require an argument");
759
760		nav[nac++] = av[0];
761		nav[nac++] = av[1];
762
763		ac -= 2;
764		av += 2;
765	}
766
767	if (ac < 1)
768		errx(1, "VPN gateway required");
769	if (ac > 1)
770		warnx("Extra arguments");
771
772	/*
773	 * Find the source address
774	 */
775	memset(&hints, 0, sizeof(hints));
776	hints.ai_family = PF_UNSPEC;
777	hints.ai_socktype = SOCK_DGRAM;
778	if (getaddrinfo(av[0], "4500", &hints, &res) != 0)
779		errx(1, "Cannot resolve destination address");
780
781	if ((src = getlocaladdr(res->ai_addr)) == NULL)
782		errx(1, "cannot find source address");
783
784	if ((srcaddr = saddr2str(src)) == NULL)
785		errx(1, "cannot read source address");
786
787	/* We get "ip[port]" strip the port */
788	if ((idx = index(srcaddr, '[')) == NULL)
789		errx(1, "unexpected source address format");
790	*idx = '\0';
791
792	nav[nac++] = isakmp;
793	nav[nac++] = inet;
794	nav[nac++] = srcaddr;
795	nav[nac++] = av[0];
796
797	return f_exchangesa(nac, nav);
798}
799
800static vchar_t *
801f_vpnd(ac, av)
802	int ac;
803	char **av;
804{
805	char *nav[] = {NULL, NULL, NULL, NULL};
806	int nac = 0;
807	char *isakmp = "isakmp";
808	char *inet = "inet";
809	char *anyaddr = "0.0.0.0";
810	char *idx;
811
812	if (ac < 1)
813		errx(1, "VPN gateway required");
814	if (ac > 1)
815		warnx("Extra arguments");
816
817	evt_filter =
818	    (EVTF_PH1DOWN|EVTF_PH1DOWN_STOP|EVTF_LOOP|EVTF_ERR|EVTF_ERR_STOP);
819
820	nav[nac++] = isakmp;
821	nav[nac++] = inet;
822	nav[nac++] = anyaddr;
823	nav[nac++] = av[0];
824
825	return f_deleteallsadst(nac, nav);
826}
827
828#ifdef ENABLE_HYBRID
829static vchar_t *
830f_logoutusr(ac, av)
831	int ac;
832	char **av;
833{
834	vchar_t *buf;
835	struct admin_com *head;
836	char *user;
837	size_t userlen;
838
839	/* need username */
840	if (ac < 1)
841		errx(1, "insufficient arguments");
842	user = av[0];
843	userlen = strlen(user);
844	if ((user == NULL) || (userlen > LOGINLEN))
845		errx(1, "bad login (too long?)");
846
847	buf = vmalloc(sizeof(*head) + userlen);
848	if (buf == NULL)
849		return NULL;
850
851	head = (struct admin_com *)buf->v;
852	head->ac_len = buf->l;
853	head->ac_cmd = ADMIN_LOGOUT_USER;
854	head->ac_errno = 0;
855	head->ac_proto = 0;
856
857	strncpy((char *)(head + 1), user, userlen);
858
859	return buf;
860}
861#endif /* ENABLE_HYBRID */
862
863
864static int
865get_proto(str)
866	char *str;
867{
868	struct proto_tag *cp;
869
870	if (str == NULL) {
871		errno = EINVAL;
872		return -1;
873	}
874
875	/* checking the string of command. */
876	for (cp = &prototab[0]; cp->str; cp++) {
877		if (strcmp(str, cp->str) == 0)
878			return cp->proto;
879	}
880
881	errno = EINVAL;
882	return -1;
883}
884
885static vchar_t *
886get_index(ac, av)
887	int ac;
888	char **av;
889{
890	int family;
891
892	if (ac != 3 && ac != 4) {
893		errno = EINVAL;
894		return NULL;
895	}
896
897	/* checking the string of family */
898	family = get_family(*av);
899	if (family == -1)
900		return NULL;
901	av++;
902	ac--;
903
904	return get_comindexes(family, ac, av);
905}
906
907static int
908get_family(str)
909	char *str;
910{
911	if (strcmp("inet", str) == 0)
912		return AF_INET;
913#ifdef INET6
914	else if (strcmp("inet6", str) == 0)
915		return AF_INET6;
916#endif
917	errno = EAFNOSUPPORT;
918	return -1;
919}
920
921static vchar_t *
922get_comindexes(family, ac, av)
923	int family;
924	int ac;
925	char **av;
926{
927	vchar_t *buf;
928	struct admin_com_indexes *ci;
929	char *p_name = NULL, *p_port = NULL;
930	char *p_prefs = NULL, *p_prefd = NULL;
931	struct sockaddr *src = NULL, *dst = NULL;
932	int ulproto;
933
934	if (ac != 2 && ac != 3) {
935		errno = EINVAL;
936		return NULL;
937	}
938
939	if (get_comindex(*av, &p_name, &p_port, &p_prefs) == -1)
940		goto bad;
941	src = get_sockaddr(family, p_name, p_port);
942	if (p_name) {
943		racoon_free(p_name);
944		p_name = NULL;
945	}
946	if (p_port) {
947		racoon_free(p_port);
948		p_port = NULL;
949	}
950	if (src == NULL)
951		goto bad;
952	av++;
953	ac--;
954	if (get_comindex(*av, &p_name, &p_port, &p_prefd) == -1)
955		goto bad;
956	dst = get_sockaddr(family, p_name, p_port);
957	if (p_name) {
958		racoon_free(p_name);
959		p_name = NULL;
960	}
961	if (p_port) {
962		racoon_free(p_port);
963		p_port = NULL;
964	}
965	if (dst == NULL)
966		goto bad;
967
968	buf = vmalloc(sizeof(*ci));
969	if (buf == NULL)
970		goto bad;
971
972	av++;
973	ac--;
974	if(ac){
975		ulproto = get_ulproto(*av);
976		if (ulproto == -1)
977			goto bad;
978	}else
979		ulproto=0;
980
981	ci = (struct admin_com_indexes *)buf->v;
982	if(p_prefs)
983		ci->prefs = (u_int8_t)atoi(p_prefs); /* XXX should be handled error. */
984	else
985		ci->prefs = 32;
986	if(p_prefd)
987		ci->prefd = (u_int8_t)atoi(p_prefd); /* XXX should be handled error. */
988	else
989		ci->prefd = 32;
990	ci->ul_proto = ulproto;
991	memcpy(&ci->src, src, sysdep_sa_len(src));
992	memcpy(&ci->dst, dst, sysdep_sa_len(dst));
993
994	if (p_name)
995		racoon_free(p_name);
996
997	return buf;
998
999   bad:
1000	if (p_name)
1001		racoon_free(p_name);
1002	if (p_port)
1003		racoon_free(p_port);
1004	if (p_prefs)
1005		racoon_free(p_prefs);
1006	if (p_prefd)
1007		racoon_free(p_prefd);
1008	return NULL;
1009}
1010
1011static int
1012get_comindex(str, name, port, pref)
1013	char *str, **name, **port, **pref;
1014{
1015	char *p;
1016
1017	*name = *port = *pref = NULL;
1018
1019	*name = racoon_strdup(str);
1020	STRDUP_FATAL(*name);
1021	p = strpbrk(*name, "/[");
1022	if (p != NULL) {
1023		if (*(p + 1) == '\0')
1024			goto bad;
1025		if (*p == '/') {
1026			*p = '\0';
1027			*pref = racoon_strdup(p + 1);
1028			STRDUP_FATAL(*pref);
1029			p = strchr(*pref, '[');
1030			if (p != NULL) {
1031				if (*(p + 1) == '\0')
1032					goto bad;
1033				*p = '\0';
1034				*port = racoon_strdup(p + 1);
1035				STRDUP_FATAL(*port);
1036				p = strchr(*pref, ']');
1037				if (p == NULL)
1038					goto bad;
1039				*p = '\0';
1040			}
1041		} else if (*p == '[') {
1042			if (*pref == NULL)
1043				goto bad;
1044			*p = '\0';
1045			*port = racoon_strdup(p + 1);
1046			STRDUP_FATAL(*port);
1047			p = strchr(*pref, ']');
1048			if (p == NULL)
1049				goto bad;
1050			*p = '\0';
1051		} else {
1052			/* XXX */
1053		}
1054	}
1055
1056	return 0;
1057
1058    bad:
1059
1060	if (*name)
1061		racoon_free(*name);
1062	if (*port)
1063		racoon_free(*port);
1064	if (*pref)
1065		racoon_free(*pref);
1066	*name = *port = *pref = NULL;
1067	return -1;
1068}
1069
1070static int
1071get_ulproto(str)
1072	char *str;
1073{
1074	struct ulproto_tag *cp;
1075
1076	if(str == NULL){
1077		errno = EINVAL;
1078		return -1;
1079	}
1080
1081	/* checking the string of upper layer protocol. */
1082	for (cp = &ulprototab[0]; cp->str; cp++) {
1083		if (strcmp(str, cp->str) == 0)
1084			return cp->ul_proto;
1085	}
1086
1087	errno = EINVAL;
1088	return -1;
1089}
1090
1091/* %%% */
1092void
1093dump_isakmp_sa(buf, len)
1094	char *buf;
1095	int len;
1096{
1097	struct ph1dump *pd;
1098	struct tm *tm;
1099	char tbuf[56];
1100	caddr_t p = NULL;
1101
1102/* isakmp status header */
1103/* short header;
1104 1234567890123456789012 0000000000000000:0000000000000000 000000000000
1105*/
1106char *header1 =
1107"Destination            Cookies                           Created";
1108
1109/* semi long header;
1110 1234567890123456789012 0000000000000000:0000000000000000 00 X 00 X 0000-00-00 00:00:00 000000
1111*/
1112char *header2 =
1113"Destination            Cookies                           ST S  V E Created             Phase2";
1114
1115/* long header;
1116 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000000000000000:0000000000000000 00 X 00 X 0000-00-00 00:00:00 000000
1117*/
1118char *header3 =
1119"Source                                        Destination                                   Cookies                           ST S  V E Created             Phase2";
1120
1121/* phase status header */
1122/* short format;
1123   side stats source address         destination address
1124   xxx  xxxxx 1234567890123456789012 1234567890123456789012
1125*/
1126
1127	static char *estr[] = { "", "B", "M", "U", "A", "I", };
1128
1129	switch (long_format) {
1130	case 0:
1131		printf("%s\n", header1);
1132		break;
1133	case 1:
1134		printf("%s\n", header2);
1135		break;
1136	case 2:
1137	default:
1138		printf("%s\n", header3);
1139		break;
1140	}
1141
1142	if (len % sizeof(*pd))
1143		printf("invalid length %d\n", len);
1144	len /= sizeof(*pd);
1145
1146	pd = (struct ph1dump *)buf;
1147
1148	while (len-- > 0) {
1149		/* source address */
1150		if (long_format >= 2) {
1151			GETNAMEINFO((struct sockaddr *)&pd->local, _addr1_, _addr2_);
1152			switch (long_format) {
1153			case 0:
1154				break;
1155			case 1:
1156				p = fixed_addr(_addr1_, _addr2_, 22);
1157				break;
1158			case 2:
1159			default:
1160				p = fixed_addr(_addr1_, _addr2_, 45);
1161				break;
1162			}
1163			printf("%s ", p);
1164		}
1165
1166		/* destination address */
1167		GETNAMEINFO((struct sockaddr *)&pd->remote, _addr1_, _addr2_);
1168		switch (long_format) {
1169		case 0:
1170		case 1:
1171			p = fixed_addr(_addr1_, _addr2_, 22);
1172			break;
1173		case 2:
1174		default:
1175			p = fixed_addr(_addr1_, _addr2_, 45);
1176			break;
1177		}
1178		printf("%s ", p);
1179
1180		printf("%s ", pindex_isakmp(&pd->index));
1181
1182		/* statuc, side and version */
1183		if (long_format >= 1) {
1184			printf("%2d %c %2x ",
1185				pd->status,
1186				pd->side == INITIATOR ? 'I' : 'R',
1187				pd->version);
1188			if (ARRAYLEN(estr) > pd->etype)
1189				printf("%s ", estr[pd->etype]);
1190		}
1191
1192		/* created date */
1193		if (pd->created) {
1194			tm = localtime(&pd->created);
1195			strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %T", tm);
1196		} else
1197			snprintf(tbuf, sizeof(tbuf), "                   ");
1198		printf("%s ", tbuf);
1199
1200		/* counter of phase 2 */
1201		if (long_format >= 1)
1202			printf("%6d ", pd->ph2cnt);
1203
1204		printf("\n");
1205
1206		pd++;
1207	}
1208
1209	return;
1210}
1211
1212/* %%% */
1213void
1214dump_internal(buf, tlen)
1215	char *buf;
1216	int tlen;
1217{
1218	struct ph2handle *iph2;
1219	struct sockaddr *addr;
1220
1221/*
1222short header;
1223 source address         destination address
1224 1234567890123456789012 1234567890123456789012
1225*/
1226char *short_h1 =
1227"Source                 Destination            ";
1228
1229/*
1230long header;
1231 source address                                destination address
1232 123456789012345678901234567890123456789012345 123456789012345678901234567890123456789012345
1233 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000:0000:0000:0000:0000:0000:0000:0000.00000
1234*/
1235char *long_h1 =
1236"Source                                        Destination                                  ";
1237
1238	printf("%s\n", long_format ? long_h1 : short_h1);
1239
1240	while (tlen > 0) {
1241		iph2 = (struct ph2handle *)buf;
1242		addr = (struct sockaddr *)(++iph2);
1243
1244		GETNAMEINFO(addr, _addr1_, _addr2_);
1245		printf("%s ", long_format ?
1246			  fixed_addr(_addr1_, _addr2_, 45)
1247			: fixed_addr(_addr1_, _addr2_, 22));
1248		addr++;
1249		tlen -= sysdep_sa_len(addr);
1250
1251		GETNAMEINFO(addr, _addr1_, _addr2_);
1252		printf("%s ", long_format ?
1253			  fixed_addr(_addr1_, _addr2_, 45)
1254			: fixed_addr(_addr1_, _addr2_, 22));
1255		addr++;
1256		tlen -= sysdep_sa_len(addr);
1257
1258		printf("\n");
1259	}
1260
1261	return;
1262}
1263
1264/* %%% */
1265char *
1266pindex_isakmp(index)
1267	isakmp_index *index;
1268{
1269	static char buf[64];
1270	u_char *p;
1271	int i, j;
1272
1273	memset(buf, 0, sizeof(buf));
1274
1275	/* copy index */
1276	p = (u_char *)index;
1277	for (j = 0, i = 0; i < sizeof(isakmp_index); i++) {
1278		snprintf((char *)&buf[j], sizeof(buf) - j, "%02x", p[i]);
1279		j += 2;
1280		switch (i) {
1281		case 7:
1282#if 0
1283		case 15:
1284#endif
1285			buf[j++] = ':';
1286		}
1287	}
1288
1289	return buf;
1290}
1291
1292/* print schedule */
1293char *str_sched_stat[] = {
1294"off",
1295"on",
1296"dead",
1297};
1298
1299char *str_sched_id[] = {
1300"PH1resend",
1301"PH1lifetime",
1302"PH2resend",
1303"PSTacquire",
1304"PSTlifetime",
1305};
1306
1307void
1308print_schedule(buf, len)
1309	caddr_t buf;
1310	int len;
1311{
1312	struct scheddump *sc = (struct scheddump *)buf;
1313	struct tm *tm;
1314	char tbuf[56];
1315
1316	if (len % sizeof(*sc))
1317		printf("invalid length %d\n", len);
1318	len /= sizeof(*sc);
1319
1320	/*      00000000 00000000 00000000 xxx........*/
1321	printf("index    tick     xtime    created\n");
1322
1323	while (len-- > 0) {
1324		tm = localtime(&sc->created);
1325		strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %T", tm);
1326
1327		printf("%-8ld %-8ld %-8ld %s\n",
1328			sc->id,
1329			(long)sc->tick,
1330			(long)sc->xtime,
1331			tbuf);
1332		sc++;
1333	}
1334
1335	return;
1336}
1337
1338
1339void
1340print_evt(buf, len)
1341	caddr_t buf;
1342	int len;
1343{
1344	struct evtdump *evtdump = (struct evtdump *)buf;
1345	int i;
1346	char *srcstr;
1347	char *dststr;
1348
1349	for (i = 0; evtmsg[i].msg; i++)
1350		if (evtmsg[i].type == evtdump->type)
1351			break;
1352
1353	if (evtmsg[i].msg == NULL)
1354		printf("Event %d: ", evtdump->type);
1355	else
1356		printf("%s : ", evtmsg[i].msg);
1357
1358	if ((srcstr = saddr2str((struct sockaddr *)&evtdump->src)) == NULL)
1359		printf("unknown");
1360	else
1361		printf("%s", srcstr);
1362	printf(" -> ");
1363	if ((dststr = saddr2str((struct sockaddr *)&evtdump->dst)) == NULL)
1364		printf("unknown");
1365	else
1366		printf("%s", dststr);
1367	printf("\n");
1368
1369	return;
1370}
1371
1372void
1373print_err(buf, len)
1374	caddr_t buf;
1375	int len;
1376{
1377	struct evtdump *evtdump = (struct evtdump *)buf;
1378	int i;
1379
1380
1381	for (i = 0; evtmsg[i].msg; i++)
1382		if (evtmsg[i].type == evtdump->type)
1383			break;
1384
1385	if (evtmsg[i].level != ERROR)
1386		return;
1387
1388	if (evtmsg[i].msg == NULL)
1389		printf("Error: Event %d\n", evtdump->type);
1390	else
1391		printf("Error: %s\n", evtmsg[i].msg);
1392
1393	if (evt_filter & EVTF_ERR_STOP)
1394		evt_filter &= ~EVTF_LOOP;
1395
1396	return;
1397}
1398
1399/*
1400 * Print a message when phase 1 SA goes down
1401 */
1402void
1403print_ph1down(buf, len)
1404	caddr_t buf;
1405	int len;
1406{
1407	struct evtdump *evtdump = (struct evtdump *)buf;
1408
1409	if (evtdump->type != EVTT_PHASE1_DOWN)
1410		return;
1411
1412	printf("VPN connexion terminated\n");
1413
1414	if (evt_filter & EVTF_PH1DOWN_STOP)
1415		evt_filter &= ~EVTF_LOOP;
1416
1417	return;
1418}
1419
1420/*
1421 * Print ISAKMP mode config info (IP and banner)
1422 */
1423void
1424print_cfg(buf, len)
1425	caddr_t buf;
1426	int len;
1427{
1428	struct evtdump *evtdump = (struct evtdump *)buf;
1429	struct isakmp_data *attr;
1430	char *banner = NULL;
1431	struct in_addr addr4;
1432
1433	memset(&addr4, 0, sizeof(addr4));
1434
1435	if (evtdump->type != EVTT_ISAKMP_CFG_DONE &&
1436	    evtdump->type != EVTT_NO_ISAKMP_CFG)
1437		return;
1438
1439	len -= sizeof(*evtdump);
1440	attr = (struct isakmp_data *)(evtdump + 1);
1441
1442	while (len > 0) {
1443		if (len < sizeof(*attr)) {
1444			printf("short attribute too short\n");
1445			break;
1446		}
1447
1448		if ((ntohs(attr->type) & ISAKMP_GEN_MASK) == ISAKMP_GEN_TV) {
1449			/* Short attribute, skip */
1450			len -= sizeof(*attr);
1451			attr++;
1452		} else { /* Long attribute */
1453			char *n;
1454
1455			if (len < (sizeof(*attr) + ntohs(attr->lorv))) {
1456				printf("long attribute too long\n");
1457				break;
1458			}
1459
1460			switch (ntohs(attr->type) & ~ISAKMP_GEN_MASK) {
1461			case INTERNAL_IP4_ADDRESS:
1462				if (ntohs(attr->lorv) < sizeof(addr4)) {
1463					printf("addr4 attribute too short\n");
1464					break;
1465				}
1466				memcpy(&addr4, attr + 1, sizeof(addr4));
1467				break;
1468
1469			case UNITY_BANNER:
1470				banner = racoon_malloc(ntohs(attr->lorv) + 1);
1471				if (banner == NULL) {
1472					printf("malloc failed\n");
1473					break;
1474				}
1475				memcpy(banner, attr + 1, ntohs(attr->lorv));
1476				banner[ntohs(attr->lorv)] = '\0';
1477				break;
1478
1479			default:
1480				break;
1481			}
1482
1483			len -= (sizeof(*attr) + ntohs(attr->lorv));
1484			n = (char *)attr;
1485			attr = (struct isakmp_data *)
1486			    (n + sizeof(*attr) + ntohs(attr->lorv));
1487		}
1488	}
1489
1490	if (evtdump->type == EVTT_ISAKMP_CFG_DONE)
1491		printf("Bound to address %s\n", inet_ntoa(addr4));
1492	else
1493		printf("VPN connexion established\n");
1494
1495	if (banner) {
1496		struct winsize win;
1497		int col = 0;
1498		int i;
1499
1500		if (ioctl(1, TIOCGWINSZ, &win) != 1)
1501			col = win.ws_col;
1502
1503		for (i = 0; i < col; i++)
1504			printf("%c", '=');
1505		printf("\n%s\n", banner);
1506		for (i = 0; i < col; i++)
1507			printf("%c", '=');
1508		printf("\n");
1509		racoon_free(banner);
1510	}
1511
1512	if (evt_filter & EVTF_CFG_STOP)
1513		evt_filter &= ~EVTF_LOOP;
1514
1515	return;
1516}
1517
1518
1519char *
1520fixed_addr(addr, port, len)
1521	char *addr, *port;
1522	int len;
1523{
1524	static char _addr_buf_[BUFSIZ];
1525	char *p;
1526	int plen, i;
1527
1528	/* initialize */
1529	memset(_addr_buf_, ' ', sizeof(_addr_buf_));
1530
1531	plen = strlen(port);
1532	if (len < plen + 1)
1533		return NULL;
1534
1535	p = _addr_buf_;
1536	for (i = 0; i < len - plen - 1 && addr[i] != '\0'; /*noting*/)
1537		*p++ = addr[i++];
1538	*p++ = '.';
1539
1540	for (i = 0; i < plen && port[i] != '\0'; /*noting*/)
1541		*p++ = port[i++];
1542
1543	_addr_buf_[len] = '\0';
1544
1545	return _addr_buf_;
1546}
1547
1548static int
1549handle_recv(combuf)
1550	vchar_t *combuf;
1551{
1552        struct admin_com h, *com;
1553        caddr_t buf;
1554        int len;
1555
1556	com = (struct admin_com *)combuf->v;
1557	len = com->ac_len - sizeof(*com);
1558	buf = combuf->v + sizeof(*com);
1559
1560	switch (com->ac_cmd) {
1561	case ADMIN_SHOW_SCHED:
1562		print_schedule(buf, len);
1563		break;
1564
1565	case ADMIN_SHOW_EVT: {
1566		struct evtdump *evtdump;
1567
1568		/* We got no event */
1569		if (len == 0) {
1570			/* If we were purging the queue, it is now done */
1571			if (evt_filter & EVTF_PURGE)
1572				evt_filter &= ~EVTF_PURGE;
1573			break;
1574		}
1575
1576		if (len < sizeof(struct evtdump))
1577			errx(1, "Short buffer\n");
1578
1579		/* Toss outdated events */
1580		evtdump = (struct evtdump *)buf;
1581		if (evtdump->timestamp < evt_start)
1582			break;
1583
1584		if (evt_filter & EVTF_ALL)
1585			print_evt(buf, len);
1586		if (evt_filter & EVTF_ERR)
1587			print_err(buf, len);
1588		if (evt_filter & EVTF_CFG)
1589			print_cfg(buf, len);
1590		if (evt_filter & EVTF_PH1DOWN)
1591			print_ph1down(buf, len);
1592		break;
1593	}
1594
1595	case ADMIN_SHOW_SA:
1596	   {
1597		switch (com->ac_proto) {
1598		case ADMIN_PROTO_ISAKMP:
1599			dump_isakmp_sa(buf, len);
1600			break;
1601		case ADMIN_PROTO_IPSEC:
1602		case ADMIN_PROTO_AH:
1603		case ADMIN_PROTO_ESP:
1604		    {
1605			struct sadb_msg *msg = (struct sadb_msg *)buf;
1606
1607			switch (msg->sadb_msg_errno) {
1608			case ENOENT:
1609				switch (msg->sadb_msg_type) {
1610				case SADB_DELETE:
1611				case SADB_GET:
1612					printf("No entry.\n");
1613					break;
1614				case SADB_DUMP:
1615					printf("No SAD entries.\n");
1616					break;
1617				}
1618				break;
1619			case 0:
1620				while (1) {
1621					pfkey_sadump(msg);
1622					if (msg->sadb_msg_seq == 0)
1623						break;
1624					msg = (struct sadb_msg *)((caddr_t)msg +
1625						     PFKEY_UNUNIT64(msg->sadb_msg_len));
1626				}
1627				break;
1628			default:
1629				printf("%s.\n", strerror(msg->sadb_msg_errno));
1630			}
1631		    }
1632			break;
1633		case ADMIN_PROTO_INTERNAL:
1634			dump_internal(buf, len);
1635			break;
1636		default:
1637			printf("Invalid proto [%d]\n", com->ac_proto);
1638		}
1639
1640	    }
1641		break;
1642
1643	default:
1644		/* IGNORE */
1645		break;
1646	}
1647
1648	close(so);
1649	return 0;
1650
1651    bad:
1652	close(so);
1653	return -1;
1654}
1655