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