racoonctl.c revision 0a1907d434839af6a9cb6329bbde60b237bf53dc
1/*	$NetBSD: racoonctl.c,v 1.7.6.1 2008/07/15 00:55:48 mgrooms 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
838	/* need username */
839	if (ac < 1)
840		errx(1, "insufficient arguments");
841	user = av[0];
842	if ((user == NULL) || (strlen(user) > LOGINLEN))
843		errx(1, "bad login (too long?)");
844
845	buf = vmalloc(sizeof(*head) + strlen(user) + 1);
846	if (buf == NULL)
847		return NULL;
848
849	head = (struct admin_com *)buf->v;
850	head->ac_len = buf->l;
851	head->ac_cmd = ADMIN_LOGOUT_USER;
852	head->ac_errno = 0;
853	head->ac_proto = 0;
854
855	strncpy((char *)(head + 1), user, LOGINLEN);
856
857	return buf;
858}
859#endif /* ENABLE_HYBRID */
860
861
862static int
863get_proto(str)
864	char *str;
865{
866	struct proto_tag *cp;
867
868	if (str == NULL) {
869		errno = EINVAL;
870		return -1;
871	}
872
873	/* checking the string of command. */
874	for (cp = &prototab[0]; cp->str; cp++) {
875		if (strcmp(str, cp->str) == 0)
876			return cp->proto;
877	}
878
879	errno = EINVAL;
880	return -1;
881}
882
883static vchar_t *
884get_index(ac, av)
885	int ac;
886	char **av;
887{
888	int family;
889
890	if (ac != 3 && ac != 4) {
891		errno = EINVAL;
892		return NULL;
893	}
894
895	/* checking the string of family */
896	family = get_family(*av);
897	if (family == -1)
898		return NULL;
899	av++;
900	ac--;
901
902	return get_comindexes(family, ac, av);
903}
904
905static int
906get_family(str)
907	char *str;
908{
909	if (strcmp("inet", str) == 0)
910		return AF_INET;
911#ifdef INET6
912	else if (strcmp("inet6", str) == 0)
913		return AF_INET6;
914#endif
915	errno = EAFNOSUPPORT;
916	return -1;
917}
918
919static vchar_t *
920get_comindexes(family, ac, av)
921	int family;
922	int ac;
923	char **av;
924{
925	vchar_t *buf;
926	struct admin_com_indexes *ci;
927	char *p_name = NULL, *p_port = NULL;
928	char *p_prefs = NULL, *p_prefd = NULL;
929	struct sockaddr *src = NULL, *dst = NULL;
930	int ulproto;
931
932	if (ac != 2 && ac != 3) {
933		errno = EINVAL;
934		return NULL;
935	}
936
937	if (get_comindex(*av, &p_name, &p_port, &p_prefs) == -1)
938		goto bad;
939	src = get_sockaddr(family, p_name, p_port);
940	if (p_name) {
941		racoon_free(p_name);
942		p_name = NULL;
943	}
944	if (p_port) {
945		racoon_free(p_port);
946		p_port = NULL;
947	}
948	if (src == NULL)
949		goto bad;
950	av++;
951	ac--;
952	if (get_comindex(*av, &p_name, &p_port, &p_prefd) == -1)
953		goto bad;
954	dst = get_sockaddr(family, p_name, p_port);
955	if (p_name) {
956		racoon_free(p_name);
957		p_name = NULL;
958	}
959	if (p_port) {
960		racoon_free(p_port);
961		p_port = NULL;
962	}
963	if (dst == NULL)
964		goto bad;
965
966	buf = vmalloc(sizeof(*ci));
967	if (buf == NULL)
968		goto bad;
969
970	av++;
971	ac--;
972	if(ac){
973		ulproto = get_ulproto(*av);
974		if (ulproto == -1)
975			goto bad;
976	}else
977		ulproto=0;
978
979	ci = (struct admin_com_indexes *)buf->v;
980	if(p_prefs)
981		ci->prefs = (u_int8_t)atoi(p_prefs); /* XXX should be handled error. */
982	else
983		ci->prefs = 32;
984	if(p_prefd)
985		ci->prefd = (u_int8_t)atoi(p_prefd); /* XXX should be handled error. */
986	else
987		ci->prefd = 32;
988	ci->ul_proto = ulproto;
989	memcpy(&ci->src, src, sysdep_sa_len(src));
990	memcpy(&ci->dst, dst, sysdep_sa_len(dst));
991
992	if (p_name)
993		racoon_free(p_name);
994
995	return buf;
996
997   bad:
998	if (p_name)
999		racoon_free(p_name);
1000	if (p_port)
1001		racoon_free(p_port);
1002	if (p_prefs)
1003		racoon_free(p_prefs);
1004	if (p_prefd)
1005		racoon_free(p_prefd);
1006	return NULL;
1007}
1008
1009static int
1010get_comindex(str, name, port, pref)
1011	char *str, **name, **port, **pref;
1012{
1013	char *p;
1014
1015	*name = *port = *pref = NULL;
1016
1017	*name = racoon_strdup(str);
1018	STRDUP_FATAL(*name);
1019	p = strpbrk(*name, "/[");
1020	if (p != NULL) {
1021		if (*(p + 1) == '\0')
1022			goto bad;
1023		if (*p == '/') {
1024			*p = '\0';
1025			*pref = racoon_strdup(p + 1);
1026			STRDUP_FATAL(*pref);
1027			p = strchr(*pref, '[');
1028			if (p != NULL) {
1029				if (*(p + 1) == '\0')
1030					goto bad;
1031				*p = '\0';
1032				*port = racoon_strdup(p + 1);
1033				STRDUP_FATAL(*port);
1034				p = strchr(*pref, ']');
1035				if (p == NULL)
1036					goto bad;
1037				*p = '\0';
1038			}
1039		} else if (*p == '[') {
1040			if (*pref == NULL)
1041				goto bad;
1042			*p = '\0';
1043			*port = racoon_strdup(p + 1);
1044			STRDUP_FATAL(*port);
1045			p = strchr(*pref, ']');
1046			if (p == NULL)
1047				goto bad;
1048			*p = '\0';
1049		} else {
1050			/* XXX */
1051		}
1052	}
1053
1054	return 0;
1055
1056    bad:
1057
1058	if (*name)
1059		racoon_free(*name);
1060	if (*port)
1061		racoon_free(*port);
1062	if (*pref)
1063		racoon_free(*pref);
1064	*name = *port = *pref = NULL;
1065	return -1;
1066}
1067
1068static int
1069get_ulproto(str)
1070	char *str;
1071{
1072	struct ulproto_tag *cp;
1073
1074	if(str == NULL){
1075		errno = EINVAL;
1076		return -1;
1077	}
1078
1079	/* checking the string of upper layer protocol. */
1080	for (cp = &ulprototab[0]; cp->str; cp++) {
1081		if (strcmp(str, cp->str) == 0)
1082			return cp->ul_proto;
1083	}
1084
1085	errno = EINVAL;
1086	return -1;
1087}
1088
1089/* %%% */
1090void
1091dump_isakmp_sa(buf, len)
1092	char *buf;
1093	int len;
1094{
1095	struct ph1dump *pd;
1096	struct tm *tm;
1097	char tbuf[56];
1098	caddr_t p = NULL;
1099
1100/* isakmp status header */
1101/* short header;
1102 1234567890123456789012 0000000000000000:0000000000000000 000000000000
1103*/
1104char *header1 =
1105"Destination            Cookies                           Created";
1106
1107/* semi long header;
1108 1234567890123456789012 0000000000000000:0000000000000000 00 X 00 X 0000-00-00 00:00:00 000000
1109*/
1110char *header2 =
1111"Destination            Cookies                           ST S  V E Created             Phase2";
1112
1113/* long header;
1114 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
1115*/
1116char *header3 =
1117"Source                                        Destination                                   Cookies                           ST S  V E Created             Phase2";
1118
1119/* phase status header */
1120/* short format;
1121   side stats source address         destination address
1122   xxx  xxxxx 1234567890123456789012 1234567890123456789012
1123*/
1124
1125	static char *estr[] = { "", "B", "M", "U", "A", "I", };
1126
1127	switch (long_format) {
1128	case 0:
1129		printf("%s\n", header1);
1130		break;
1131	case 1:
1132		printf("%s\n", header2);
1133		break;
1134	case 2:
1135	default:
1136		printf("%s\n", header3);
1137		break;
1138	}
1139
1140	if (len % sizeof(*pd))
1141		printf("invalid length %d\n", len);
1142	len /= sizeof(*pd);
1143
1144	pd = (struct ph1dump *)buf;
1145
1146	while (len-- > 0) {
1147		/* source address */
1148		if (long_format >= 2) {
1149			GETNAMEINFO((struct sockaddr *)&pd->local, _addr1_, _addr2_);
1150			switch (long_format) {
1151			case 0:
1152				break;
1153			case 1:
1154				p = fixed_addr(_addr1_, _addr2_, 22);
1155				break;
1156			case 2:
1157			default:
1158				p = fixed_addr(_addr1_, _addr2_, 45);
1159				break;
1160			}
1161			printf("%s ", p);
1162		}
1163
1164		/* destination address */
1165		GETNAMEINFO((struct sockaddr *)&pd->remote, _addr1_, _addr2_);
1166		switch (long_format) {
1167		case 0:
1168		case 1:
1169			p = fixed_addr(_addr1_, _addr2_, 22);
1170			break;
1171		case 2:
1172		default:
1173			p = fixed_addr(_addr1_, _addr2_, 45);
1174			break;
1175		}
1176		printf("%s ", p);
1177
1178		printf("%s ", pindex_isakmp(&pd->index));
1179
1180		/* statuc, side and version */
1181		if (long_format >= 1) {
1182			printf("%2d %c %2x ",
1183				pd->status,
1184				pd->side == INITIATOR ? 'I' : 'R',
1185				pd->version);
1186			if (ARRAYLEN(estr) > pd->etype)
1187				printf("%s ", estr[pd->etype]);
1188		}
1189
1190		/* created date */
1191		if (pd->created) {
1192			tm = localtime(&pd->created);
1193			strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %T", tm);
1194		} else
1195			snprintf(tbuf, sizeof(tbuf), "                   ");
1196		printf("%s ", tbuf);
1197
1198		/* counter of phase 2 */
1199		if (long_format >= 1)
1200			printf("%6d ", pd->ph2cnt);
1201
1202		printf("\n");
1203
1204		pd++;
1205	}
1206
1207	return;
1208}
1209
1210/* %%% */
1211void
1212dump_internal(buf, tlen)
1213	char *buf;
1214	int tlen;
1215{
1216	struct ph2handle *iph2;
1217	struct sockaddr *addr;
1218
1219/*
1220short header;
1221 source address         destination address
1222 1234567890123456789012 1234567890123456789012
1223*/
1224char *short_h1 =
1225"Source                 Destination            ";
1226
1227/*
1228long header;
1229 source address                                destination address
1230 123456789012345678901234567890123456789012345 123456789012345678901234567890123456789012345
1231 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
1232*/
1233char *long_h1 =
1234"Source                                        Destination                                  ";
1235
1236	printf("%s\n", long_format ? long_h1 : short_h1);
1237
1238	while (tlen > 0) {
1239		iph2 = (struct ph2handle *)buf;
1240		addr = (struct sockaddr *)(++iph2);
1241
1242		GETNAMEINFO(addr, _addr1_, _addr2_);
1243		printf("%s ", long_format ?
1244			  fixed_addr(_addr1_, _addr2_, 45)
1245			: fixed_addr(_addr1_, _addr2_, 22));
1246		addr++;
1247		tlen -= sysdep_sa_len(addr);
1248
1249		GETNAMEINFO(addr, _addr1_, _addr2_);
1250		printf("%s ", long_format ?
1251			  fixed_addr(_addr1_, _addr2_, 45)
1252			: fixed_addr(_addr1_, _addr2_, 22));
1253		addr++;
1254		tlen -= sysdep_sa_len(addr);
1255
1256		printf("\n");
1257	}
1258
1259	return;
1260}
1261
1262/* %%% */
1263char *
1264pindex_isakmp(index)
1265	isakmp_index *index;
1266{
1267	static char buf[64];
1268	u_char *p;
1269	int i, j;
1270
1271	memset(buf, 0, sizeof(buf));
1272
1273	/* copy index */
1274	p = (u_char *)index;
1275	for (j = 0, i = 0; i < sizeof(isakmp_index); i++) {
1276		snprintf((char *)&buf[j], sizeof(buf) - j, "%02x", p[i]);
1277		j += 2;
1278		switch (i) {
1279		case 7:
1280#if 0
1281		case 15:
1282#endif
1283			buf[j++] = ':';
1284		}
1285	}
1286
1287	return buf;
1288}
1289
1290/* print schedule */
1291char *str_sched_stat[] = {
1292"off",
1293"on",
1294"dead",
1295};
1296
1297char *str_sched_id[] = {
1298"PH1resend",
1299"PH1lifetime",
1300"PH2resend",
1301"PSTacquire",
1302"PSTlifetime",
1303};
1304
1305void
1306print_schedule(buf, len)
1307	caddr_t buf;
1308	int len;
1309{
1310	struct scheddump *sc = (struct scheddump *)buf;
1311	struct tm *tm;
1312	char tbuf[56];
1313
1314	if (len % sizeof(*sc))
1315		printf("invalid length %d\n", len);
1316	len /= sizeof(*sc);
1317
1318	/*      00000000 00000000 00000000 xxx........*/
1319	printf("index    tick     xtime    created\n");
1320
1321	while (len-- > 0) {
1322		tm = localtime(&sc->created);
1323		strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %T", tm);
1324
1325		printf("%-8ld %-8ld %-8ld %s\n",
1326			sc->id,
1327			(long)sc->tick,
1328			(long)sc->xtime,
1329			tbuf);
1330		sc++;
1331	}
1332
1333	return;
1334}
1335
1336
1337void
1338print_evt(buf, len)
1339	caddr_t buf;
1340	int len;
1341{
1342	struct evtdump *evtdump = (struct evtdump *)buf;
1343	int i;
1344	char *srcstr;
1345	char *dststr;
1346
1347	for (i = 0; evtmsg[i].msg; i++)
1348		if (evtmsg[i].type == evtdump->type)
1349			break;
1350
1351	if (evtmsg[i].msg == NULL)
1352		printf("Event %d: ", evtdump->type);
1353	else
1354		printf("%s : ", evtmsg[i].msg);
1355
1356	if ((srcstr = saddr2str((struct sockaddr *)&evtdump->src)) == NULL)
1357		printf("unknown");
1358	else
1359		printf("%s", srcstr);
1360	printf(" -> ");
1361	if ((dststr = saddr2str((struct sockaddr *)&evtdump->dst)) == NULL)
1362		printf("unknown");
1363	else
1364		printf("%s", dststr);
1365	printf("\n");
1366
1367	return;
1368}
1369
1370void
1371print_err(buf, len)
1372	caddr_t buf;
1373	int len;
1374{
1375	struct evtdump *evtdump = (struct evtdump *)buf;
1376	int i;
1377
1378
1379	for (i = 0; evtmsg[i].msg; i++)
1380		if (evtmsg[i].type == evtdump->type)
1381			break;
1382
1383	if (evtmsg[i].level != ERROR)
1384		return;
1385
1386	if (evtmsg[i].msg == NULL)
1387		printf("Error: Event %d\n", evtdump->type);
1388	else
1389		printf("Error: %s\n", evtmsg[i].msg);
1390
1391	if (evt_filter & EVTF_ERR_STOP)
1392		evt_filter &= ~EVTF_LOOP;
1393
1394	return;
1395}
1396
1397/*
1398 * Print a message when phase 1 SA goes down
1399 */
1400void
1401print_ph1down(buf, len)
1402	caddr_t buf;
1403	int len;
1404{
1405	struct evtdump *evtdump = (struct evtdump *)buf;
1406
1407	if (evtdump->type != EVTT_PHASE1_DOWN)
1408		return;
1409
1410	printf("VPN connexion terminated\n");
1411
1412	if (evt_filter & EVTF_PH1DOWN_STOP)
1413		evt_filter &= ~EVTF_LOOP;
1414
1415	return;
1416}
1417
1418/*
1419 * Print ISAKMP mode config info (IP and banner)
1420 */
1421void
1422print_cfg(buf, len)
1423	caddr_t buf;
1424	int len;
1425{
1426	struct evtdump *evtdump = (struct evtdump *)buf;
1427	struct isakmp_data *attr;
1428	char *banner = NULL;
1429	struct in_addr addr4;
1430
1431	memset(&addr4, 0, sizeof(addr4));
1432
1433	if (evtdump->type != EVTT_ISAKMP_CFG_DONE &&
1434	    evtdump->type != EVTT_NO_ISAKMP_CFG)
1435		return;
1436
1437	len -= sizeof(*evtdump);
1438	attr = (struct isakmp_data *)(evtdump + 1);
1439
1440	while (len > 0) {
1441		if (len < sizeof(*attr)) {
1442			printf("short attribute too short\n");
1443			break;
1444		}
1445
1446		if ((ntohs(attr->type) & ISAKMP_GEN_MASK) == ISAKMP_GEN_TV) {
1447			/* Short attribute, skip */
1448			len -= sizeof(*attr);
1449			attr++;
1450		} else { /* Long attribute */
1451			char *n;
1452
1453			if (len < (sizeof(*attr) + ntohs(attr->lorv))) {
1454				printf("long attribute too long\n");
1455				break;
1456			}
1457
1458			switch (ntohs(attr->type) & ~ISAKMP_GEN_MASK) {
1459			case INTERNAL_IP4_ADDRESS:
1460				if (ntohs(attr->lorv) < sizeof(addr4)) {
1461					printf("addr4 attribute too short\n");
1462					break;
1463				}
1464				memcpy(&addr4, attr + 1, sizeof(addr4));
1465				break;
1466
1467			case UNITY_BANNER:
1468				banner = racoon_malloc(ntohs(attr->lorv) + 1);
1469				if (banner == NULL) {
1470					printf("malloc failed\n");
1471					break;
1472				}
1473				memcpy(banner, attr + 1, ntohs(attr->lorv));
1474				banner[ntohs(attr->lorv)] = '\0';
1475				break;
1476
1477			default:
1478				break;
1479			}
1480
1481			len -= (sizeof(*attr) + ntohs(attr->lorv));
1482			n = (char *)attr;
1483			attr = (struct isakmp_data *)
1484			    (n + sizeof(*attr) + ntohs(attr->lorv));
1485		}
1486	}
1487
1488	if (evtdump->type == EVTT_ISAKMP_CFG_DONE)
1489		printf("Bound to address %s\n", inet_ntoa(addr4));
1490	else
1491		printf("VPN connexion established\n");
1492
1493	if (banner) {
1494		struct winsize win;
1495		int col = 0;
1496		int i;
1497
1498		if (ioctl(1, TIOCGWINSZ, &win) != 1)
1499			col = win.ws_col;
1500
1501		for (i = 0; i < col; i++)
1502			printf("%c", '=');
1503		printf("\n%s\n", banner);
1504		for (i = 0; i < col; i++)
1505			printf("%c", '=');
1506		printf("\n");
1507		racoon_free(banner);
1508	}
1509
1510	if (evt_filter & EVTF_CFG_STOP)
1511		evt_filter &= ~EVTF_LOOP;
1512
1513	return;
1514}
1515
1516
1517char *
1518fixed_addr(addr, port, len)
1519	char *addr, *port;
1520	int len;
1521{
1522	static char _addr_buf_[BUFSIZ];
1523	char *p;
1524	int plen, i;
1525
1526	/* initialize */
1527	memset(_addr_buf_, ' ', sizeof(_addr_buf_));
1528
1529	plen = strlen(port);
1530	if (len < plen + 1)
1531		return NULL;
1532
1533	p = _addr_buf_;
1534	for (i = 0; i < len - plen - 1 && addr[i] != '\0'; /*noting*/)
1535		*p++ = addr[i++];
1536	*p++ = '.';
1537
1538	for (i = 0; i < plen && port[i] != '\0'; /*noting*/)
1539		*p++ = port[i++];
1540
1541	_addr_buf_[len] = '\0';
1542
1543	return _addr_buf_;
1544}
1545
1546static int
1547handle_recv(combuf)
1548	vchar_t *combuf;
1549{
1550        struct admin_com h, *com;
1551        caddr_t buf;
1552        int len;
1553
1554	com = (struct admin_com *)combuf->v;
1555	len = com->ac_len - sizeof(*com);
1556	buf = combuf->v + sizeof(*com);
1557
1558	switch (com->ac_cmd) {
1559	case ADMIN_SHOW_SCHED:
1560		print_schedule(buf, len);
1561		break;
1562
1563	case ADMIN_SHOW_EVT: {
1564		struct evtdump *evtdump;
1565
1566		/* We got no event */
1567		if (len == 0) {
1568			/* If we were purging the queue, it is now done */
1569			if (evt_filter & EVTF_PURGE)
1570				evt_filter &= ~EVTF_PURGE;
1571			break;
1572		}
1573
1574		if (len < sizeof(struct evtdump))
1575			errx(1, "Short buffer\n");
1576
1577		/* Toss outdated events */
1578		evtdump = (struct evtdump *)buf;
1579		if (evtdump->timestamp < evt_start)
1580			break;
1581
1582		if (evt_filter & EVTF_ALL)
1583			print_evt(buf, len);
1584		if (evt_filter & EVTF_ERR)
1585			print_err(buf, len);
1586		if (evt_filter & EVTF_CFG)
1587			print_cfg(buf, len);
1588		if (evt_filter & EVTF_PH1DOWN)
1589			print_ph1down(buf, len);
1590		break;
1591	}
1592
1593	case ADMIN_SHOW_SA:
1594	   {
1595		switch (com->ac_proto) {
1596		case ADMIN_PROTO_ISAKMP:
1597			dump_isakmp_sa(buf, len);
1598			break;
1599		case ADMIN_PROTO_IPSEC:
1600		case ADMIN_PROTO_AH:
1601		case ADMIN_PROTO_ESP:
1602		    {
1603			struct sadb_msg *msg = (struct sadb_msg *)buf;
1604
1605			switch (msg->sadb_msg_errno) {
1606			case ENOENT:
1607				switch (msg->sadb_msg_type) {
1608				case SADB_DELETE:
1609				case SADB_GET:
1610					printf("No entry.\n");
1611					break;
1612				case SADB_DUMP:
1613					printf("No SAD entries.\n");
1614					break;
1615				}
1616				break;
1617			case 0:
1618				while (1) {
1619					pfkey_sadump(msg);
1620					if (msg->sadb_msg_seq == 0)
1621						break;
1622					msg = (struct sadb_msg *)((caddr_t)msg +
1623						     PFKEY_UNUNIT64(msg->sadb_msg_len));
1624				}
1625				break;
1626			default:
1627				printf("%s.\n", strerror(msg->sadb_msg_errno));
1628			}
1629		    }
1630			break;
1631		case ADMIN_PROTO_INTERNAL:
1632			dump_internal(buf, len);
1633			break;
1634		default:
1635			printf("Invalid proto [%d]\n", com->ac_proto);
1636		}
1637
1638	    }
1639		break;
1640
1641	default:
1642		/* IGNORE */
1643		break;
1644	}
1645
1646	close(so);
1647	return 0;
1648
1649    bad:
1650	close(so);
1651	return -1;
1652}
1653