No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / ipsec-tools / src / racoon / racoonctl.c
blob155c078ab5da594d6dbd91c8ef782c5262e41b19
1 /* $NetBSD: racoonctl.c,v 1.16 2009/03/12 10:57:26 tteras Exp $ */
3 /* Id: racoonctl.c,v 1.11 2006/04/06 17:06:25 manubsd Exp */
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.
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.
35 #include "config.h"
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/socket.h>
40 #include <sys/un.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <net/pfkeyv2.h>
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>
68 #include "var.h"
69 #include "vmbuf.h"
70 #include "misc.h"
71 #include "gcmalloc.h"
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"
88 char *adminsock_path = ADMINSOCK_PATH;
90 static void usage __P((void));
91 static vchar_t *get_combuf __P((int, char **));
92 static int handle_recv __P((vchar_t *));
93 static vchar_t *f_reload __P((int, char **));
94 static vchar_t *f_getsched __P((int, char **));
95 static vchar_t *f_getsa __P((int, char **));
96 static vchar_t *f_getsacert __P((int, char **));
97 static vchar_t *f_flushsa __P((int, char **));
98 static vchar_t *f_deletesa __P((int, char **));
99 static vchar_t *f_exchangesa __P((int, char **));
100 static vchar_t *f_vpnc __P((int, char **));
101 static vchar_t *f_vpnd __P((int, char **));
102 static vchar_t *f_getevt __P((int, char **));
103 #ifdef ENABLE_HYBRID
104 static vchar_t *f_logoutusr __P((int, char **));
105 #endif
107 struct 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 },
138 struct evtmsg {
139 int type;
140 char *msg;
141 } evtmsg[] = {
142 { EVT_RACOON_QUIT, "Racoon terminated" },
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" },
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" },
161 static vchar_t *get_proto_and_index __P((int, char **, u_int16_t *));
162 static int get_proto __P((char *));
163 static vchar_t *get_index __P((int, char **));
164 static int get_family __P((char *));
165 static vchar_t *get_comindexes __P((int, int, char **));
166 static int get_comindex __P((char *, char **, char **, char **));
167 static int get_ulproto __P((char *));
169 struct 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 },
181 struct 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 },
193 int so;
195 static char _addr1_[NI_MAXHOST], _addr2_[NI_MAXHOST];
197 char *pname;
198 int long_format = 0;
199 int evt_quit_event = 0;
201 void dump_isakmp_sa __P((char *, int));
202 void dump_internal __P((char *, int));
203 char *pindex_isakmp __P((isakmp_index *));
204 void print_schedule __P((caddr_t, int));
205 void print_evt __P((struct evt_async *));
206 char * fixed_addr __P((char *, char *, int));
208 static void
209 usage()
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);
244 * Check for proper racoonctl interface
246 #if ((RACOONCTL_INTERFACE_MAJOR != 1) || (RACOONCTL_INTERFACE < 20041230))
247 #error "Incompatible racoonctl interface"
248 #endif
251 main(ac, av)
252 int ac;
253 char **av;
255 vchar_t *combuf;
256 int c;
258 pname = *av;
261 * Check for proper racoonctl interface
263 if ((racoonctl_interface_major != RACOONCTL_INTERFACE_MAJOR) ||
264 (racoonctl_interface < RACOONCTL_INTERFACE))
265 errx(1, "Incompatible racoonctl interface");
267 #ifdef __linux__
269 * Disable GNU extensions that will prevent racoonct vc -u login
270 * from working (GNU getopt(3) does not like options after vc)
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;
280 case 'd':
281 loglevel++;
282 break;
284 case 's':
285 adminsock_path = optarg;
286 break;
288 default:
289 usage();
290 exit(0);
294 ac -= optind;
295 av += optind;
297 combuf = get_combuf(ac, av);
298 if (!combuf)
299 err(1, "kmpstat");
301 if (loglevel)
302 racoon_hexdump(combuf, ((struct admin_com *)combuf)->ac_len);
304 com_init();
306 if (com_send(combuf) != 0)
307 goto bad;
309 vfree(combuf);
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);
319 close(so);
320 exit(0);
322 bad:
323 close(so);
324 if (errno == EEXIST)
325 exit(0);
326 exit(1);
329 /* %%% */
331 * return command buffer.
333 static vchar_t *
334 get_combuf(ac, av)
335 int ac;
336 char **av;
338 struct cmd_tag *cp;
340 if (ac == 0) {
341 usage();
342 exit(0);
345 /* checking the string of command. */
346 for (cp = &cmdtab[0]; cp->str; cp++) {
347 if (strcmp(*av, cp->str) == 0) {
348 break;
351 if (!cp->str) {
352 printf("Invalid command [%s]\n", *av);
353 errno = EINVAL;
354 return NULL;
357 ac--;
358 av++;
359 return (cp->func)(ac, av);
362 static vchar_t *
363 make_request(u_int16_t cmd, u_int16_t proto, size_t len)
365 vchar_t *buf;
366 struct admin_com *head;
368 buf = vmalloc(sizeof(struct admin_com) + len);
369 if (buf == NULL)
370 errx(1, "not enough core");
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;
378 return buf;
381 static vchar_t *
382 f_reload(ac, av)
383 int ac;
384 char **av;
386 return make_request(ADMIN_RELOAD_CONF, 0, 0);
389 static vchar_t *
390 f_getevt(ac, av)
391 int ac;
392 char **av;
394 evt_quit_event = -1;
395 if (ac >= 1)
396 errx(1, "too many arguments");
398 return make_request(ADMIN_SHOW_EVT, 0, 0);
401 static vchar_t *
402 f_getsched(ac, av)
403 int ac;
404 char **av;
406 return make_request(ADMIN_SHOW_SCHED, 0, 0);
409 static vchar_t *
410 f_getsa(ac, av)
411 int ac;
412 char **av;
414 int proto;
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);
423 return make_request(ADMIN_SHOW_SA, proto, 0);
426 static vchar_t *
427 f_getsacert(ac, av)
428 int ac;
429 char **av;
431 vchar_t *buf, *index;
432 struct admin_com_indexes *com;
434 index = get_index(ac, av);
435 if (index == NULL)
436 return NULL;
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");
443 memcpy(buf->v+sizeof(struct admin_com), index->v, index->l);
445 vfree(index);
447 return buf;
450 static vchar_t *
451 f_flushsa(ac, av)
452 int ac;
453 char **av;
455 vchar_t *buf;
456 struct admin_com *head;
457 int proto;
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);
466 return make_request(ADMIN_FLUSH_SA, proto, 0);
469 static vchar_t *
470 f_deletesa(ac, av)
471 int ac;
472 char **av;
474 vchar_t *buf, *index;
475 int proto;
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);
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;
504 buf = make_request(ADMIN_DELETE_SA, proto, index->l);
505 if (buf == NULL)
506 goto out;
508 memcpy(buf->v + sizeof(struct admin_com), index->v, index->l);
510 out:
511 if (index != NULL)
512 vfree(index);
514 return buf;
517 static vchar_t *
518 f_deleteallsadst(ac, av)
519 int ac;
520 char **av;
522 vchar_t *buf, *index;
523 u_int16_t proto;
525 index = get_proto_and_index(ac, av, &proto);
526 if (index == NULL)
527 return NULL;
529 buf = make_request(ADMIN_DELETE_ALL_SA_DST, proto, index->l);
530 if (buf == NULL)
531 goto out;
533 memcpy(buf->v+sizeof(struct admin_com), index->v, index->l);
535 out:
536 if (index != NULL)
537 vfree(index);
539 return buf;
542 static vchar_t *
543 f_exchangesa(ac, av)
544 int ac;
545 char **av;
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;
557 if (ac < 1)
558 errx(1, "insufficient arguments");
560 /* Optional -u identity */
561 if (strcmp(av[0], "-u") == 0) {
562 if (ac < 2)
563 errx(1, "-u require an argument");
565 id = av[1];
566 if ((key = getpass("Password: ")) == NULL)
567 errx(1, "getpass() failed: %s", strerror(errno));
569 com_len += sizeof(*acp) + strlen(id) + 1 + strlen(key) + 1;
570 cmd = ADMIN_ESTABLISH_SA_PSK;
572 av += 2;
573 ac -= 2;
576 if (ac >= 2 && strcmp(av[0], "-n") == 0) {
577 /* Remoteconf name */
578 remoteconf = av[1];
579 av += 2;
580 ac -= 2;
583 if (ac >= 1 && strcmp(av[0], "-w") == 0) {
584 wait = 1;
585 av++;
586 ac--;
589 index = get_proto_and_index(ac, av, &proto);
590 if (index == NULL)
591 return NULL;
593 if (proto == ADMIN_PROTO_ISAKMP && cmd == ADMIN_ESTABLISH_SA &&
594 remoteconf != NULL)
595 com_len += strlen(remoteconf) + 1;
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;
612 com_len += index->l;
613 buf = make_request(cmd, proto, com_len);
614 if (buf == NULL)
615 errx(1, "Cannot allocate buffer");
617 memcpy(buf->v+sizeof(struct admin_com), index->v, index->l);
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);
628 acp->id_type = IDTYPE_USERFQDN;
629 acp->id_len = strlen(id) + 1;
630 acp->key_len = strlen(key) + 1;
632 data = (char *)(acp + 1);
633 strcpy(data, id);
635 data = (char *)(data + acp->id_len);
636 strcpy(data, key);
639 vfree(index);
641 return buf;
644 static vchar_t *
645 f_vpnc(ac, av)
646 int ac;
647 char **av;
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;
658 if (ac < 1)
659 errx(1, "insufficient arguments");
661 evt_quit_event = EVT_PHASE1_MODE_CFG;
663 /* Optional -u identity */
664 if (strcmp(av[0], "-u") == 0) {
665 if (ac < 2)
666 errx(1, "-u require an argument");
668 nav[nac++] = av[0];
669 nav[nac++] = av[1];
671 ac -= 2;
672 av += 2;
675 if (ac < 1)
676 errx(1, "VPN gateway required");
677 if (ac > 1)
678 warnx("Extra arguments");
681 * Find the source address
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");
689 if ((src = getlocaladdr(res->ai_addr)) == NULL)
690 errx(1, "cannot find source address");
692 if ((srcaddr = saddr2str(src)) == NULL)
693 errx(1, "cannot read source address");
695 /* We get "ip[port]" strip the port */
696 if ((idx = index(srcaddr, '[')) == NULL)
697 errx(1, "unexpected source address format");
698 *idx = '\0';
700 nav[nac++] = isakmp;
701 nav[nac++] = inet;
702 nav[nac++] = srcaddr;
703 nav[nac++] = av[0];
705 return f_exchangesa(nac, nav);
708 static vchar_t *
709 f_vpnd(ac, av)
710 int ac;
711 char **av;
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;
720 if (ac < 1)
721 errx(1, "VPN gateway required");
722 if (ac > 1)
723 warnx("Extra arguments");
725 evt_quit_event = EVT_PHASE1_DOWN;
727 nav[nac++] = isakmp;
728 nav[nac++] = inet;
729 nav[nac++] = anyaddr;
730 nav[nac++] = av[0];
732 return f_deleteallsadst(nac, nav);
735 #ifdef ENABLE_HYBRID
736 static vchar_t *
737 f_logoutusr(ac, av)
738 int ac;
739 char **av;
741 vchar_t *buf;
742 char *user;
743 size_t userlen;
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?)");
753 buf = make_request(ADMIN_LOGOUT_USER, 0, userlen);
754 if (buf == NULL)
755 return NULL;
757 strncpy(buf->v + sizeof(struct admin_com), user, userlen);
759 return buf;
761 #endif /* ENABLE_HYBRID */
763 static vchar_t *
764 get_proto_and_index(ac, av, proto)
765 int ac;
766 char **av;
767 u_int16_t *proto;
769 vchar_t *index = NULL;
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);
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;
791 return index;
794 static int
795 get_proto(str)
796 char *str;
798 struct proto_tag *cp;
800 if (str == NULL) {
801 errno = EINVAL;
802 return -1;
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;
811 errno = EINVAL;
812 return -1;
815 static vchar_t *
816 get_index(ac, av)
817 int ac;
818 char **av;
820 int family;
822 if (ac != 3 && ac != 4) {
823 errno = EINVAL;
824 return NULL;
827 /* checking the string of family */
828 family = get_family(*av);
829 if (family == -1)
830 return NULL;
831 av++;
832 ac--;
834 return get_comindexes(family, ac, av);
837 static int
838 get_family(str)
839 char *str;
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;
851 static vchar_t *
852 get_comindexes(family, ac, av)
853 int family;
854 int ac;
855 char **av;
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;
864 if (ac != 2 && ac != 3) {
865 errno = EINVAL;
866 return NULL;
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;
876 if (p_port) {
877 racoon_free(p_port);
878 p_port = NULL;
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;
891 if (p_port) {
892 racoon_free(p_port);
893 p_port = NULL;
895 if (dst == NULL)
896 goto bad;
898 buf = vmalloc(sizeof(*ci));
899 if (buf == NULL)
900 goto bad;
902 av++;
903 ac--;
904 if(ac){
905 ulproto = get_ulproto(*av);
906 if (ulproto == -1)
907 goto bad;
908 }else
909 ulproto=0;
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));
924 if (p_name)
925 racoon_free(p_name);
927 return buf;
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;
941 static int
942 get_comindex(str, name, port, pref)
943 char *str, **name, **port, **pref;
945 char *p;
947 *name = *port = *pref = NULL;
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';
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 */
986 return 0;
988 bad:
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;
1000 static int
1001 get_ulproto(str)
1002 char *str;
1004 struct ulproto_tag *cp;
1006 if(str == NULL){
1007 errno = EINVAL;
1008 return -1;
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;
1017 errno = EINVAL;
1018 return -1;
1021 /* %%% */
1022 void
1023 dump_isakmp_sa(buf, len)
1024 char *buf;
1025 int len;
1027 struct ph1dump *pd;
1028 struct tm *tm;
1029 char tbuf[56];
1030 caddr_t p = NULL;
1032 /* isakmp status header */
1033 /* short header;
1034 1234567890123456789012 0000000000000000:0000000000000000 000000000000
1036 char *header1 =
1037 "Destination Cookies Created";
1039 /* semi long header;
1040 1234567890123456789012 0000000000000000:0000000000000000 00 X 00 X 0000-00-00 00:00:00 000000
1042 char *header2 =
1043 "Destination Cookies ST S V E Created Phase2";
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
1048 char *header3 =
1049 "Source Destination Cookies ST S V E Created Phase2";
1051 /* phase status header */
1052 /* short format;
1053 side stats source address destination address
1054 xxx xxxxx 1234567890123456789012 1234567890123456789012
1057 static char *estr[] = { "", "B", "M", "U", "A", "I", };
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;
1072 if (len % sizeof(*pd))
1073 printf("invalid length %d\n", len);
1074 len /= sizeof(*pd);
1076 pd = (struct ph1dump *)buf;
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;
1093 printf("%s ", p);
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;
1108 printf("%s ", p);
1110 printf("%s ", pindex_isakmp(&pd->index));
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]);
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);
1130 /* counter of phase 2 */
1131 if (long_format >= 1)
1132 printf("%6d ", pd->ph2cnt);
1134 printf("\n");
1136 pd++;
1139 return;
1142 /* %%% */
1143 void
1144 dump_internal(buf, tlen)
1145 char *buf;
1146 int tlen;
1148 struct ph2handle *iph2;
1149 struct sockaddr *addr;
1152 short header;
1153 source address destination address
1154 1234567890123456789012 1234567890123456789012
1156 char *short_h1 =
1157 "Source Destination ";
1160 long 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
1165 char *long_h1 =
1166 "Source Destination ";
1168 printf("%s\n", long_format ? long_h1 : short_h1);
1170 while (tlen > 0) {
1171 iph2 = (struct ph2handle *)buf;
1172 addr = (struct sockaddr *)(++iph2);
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);
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);
1188 printf("\n");
1191 return;
1194 /* %%% */
1195 char *
1196 pindex_isakmp(index)
1197 isakmp_index *index;
1199 static char buf[64];
1200 u_char *p;
1201 int i, j;
1203 memset(buf, 0, sizeof(buf));
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++] = ':';
1219 return buf;
1222 /* print schedule */
1223 char *str_sched_stat[] = {
1224 "off",
1225 "on",
1226 "dead",
1229 char *str_sched_id[] = {
1230 "PH1resend",
1231 "PH1lifetime",
1232 "PH2resend",
1233 "PSTacquire",
1234 "PSTlifetime",
1237 void
1238 print_schedule(buf, len)
1239 caddr_t buf;
1240 int len;
1242 struct scheddump *sc = (struct scheddump *)buf;
1243 struct tm *tm;
1244 char tbuf[56];
1246 if (len % sizeof(*sc))
1247 printf("invalid length %d\n", len);
1248 len /= sizeof(*sc);
1250 /* 00000000 00000000 00000000 xxx........*/
1251 printf("index tick xtime created\n");
1253 while (len-- > 0) {
1254 tm = localtime(&sc->created);
1255 strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %T", tm);
1257 printf("%-8ld %-8ld %-8ld %s\n",
1258 sc->id,
1259 (long)sc->tick,
1260 (long)sc->xtime,
1261 tbuf);
1262 sc++;
1265 return;
1269 void
1270 print_evt(evtdump)
1271 struct evt_async *evtdump;
1273 int i;
1274 char *srcstr;
1275 char *dststr;
1277 for (i = 0; i < sizeof(evtmsg) / sizeof(evtmsg[0]); i++)
1278 if (evtmsg[i].type == evtdump->ec_type)
1279 break;
1281 if (evtmsg[i].msg == NULL)
1282 printf("Event %d: ", evtdump->ec_type);
1283 else
1284 printf("%s : ", evtmsg[i].msg);
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");
1299 * Print ISAKMP mode config info (IP and banner)
1301 void
1302 print_cfg(buf, len)
1303 caddr_t buf;
1304 int len;
1306 struct evt_async *evtdump = (struct evt_async *)buf;
1307 struct isakmp_data *attr;
1308 char *banner = NULL;
1309 struct in_addr addr4;
1311 memset(&addr4, 0, sizeof(addr4));
1313 if (evtdump->ec_type != EVT_PHASE1_MODE_CFG)
1314 return;
1316 len -= sizeof(*evtdump);
1317 attr = (struct isakmp_data *)(evtdump + 1);
1319 while (len > 0) {
1320 if (len < sizeof(*attr)) {
1321 printf("short attribute too short\n");
1322 break;
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;
1332 if (len < (sizeof(*attr) + ntohs(attr->lorv))) {
1333 printf("long attribute too long\n");
1334 break;
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;
1343 memcpy(&addr4, attr + 1, sizeof(addr4));
1344 break;
1346 case UNITY_BANNER:
1347 banner = racoon_malloc(ntohs(attr->lorv) + 1);
1348 if (banner == NULL) {
1349 printf("malloc failed\n");
1350 break;
1352 memcpy(banner, attr + 1, ntohs(attr->lorv));
1353 banner[ntohs(attr->lorv)] = '\0';
1354 break;
1356 default:
1357 break;
1360 len -= (sizeof(*attr) + ntohs(attr->lorv));
1361 n = (char *)attr;
1362 attr = (struct isakmp_data *)
1363 (n + sizeof(*attr) + ntohs(attr->lorv));
1367 if (len > 0)
1368 printf("Bound to address %s\n", inet_ntoa(addr4));
1369 else
1370 printf("VPN connexion established\n");
1372 if (banner) {
1373 struct winsize win;
1374 int col = 0;
1375 int i;
1377 if (ioctl(1, TIOCGWINSZ, &win) != 1)
1378 col = win.ws_col;
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);
1391 char *
1392 fixed_addr(addr, port, len)
1393 char *addr, *port;
1394 int len;
1396 static char _addr_buf_[BUFSIZ];
1397 char *p;
1398 int plen, i;
1400 /* initialize */
1401 memset(_addr_buf_, ' ', sizeof(_addr_buf_));
1403 plen = strlen(port);
1404 if (len < plen + 1)
1405 return NULL;
1407 p = _addr_buf_;
1408 for (i = 0; i < len - plen - 1 && addr[i] != '\0'; /*noting*/)
1409 *p++ = addr[i++];
1410 *p++ = '.';
1412 for (i = 0; i < plen && port[i] != '\0'; /*noting*/)
1413 *p++ = port[i++];
1415 _addr_buf_[len] = '\0';
1417 return _addr_buf_;
1420 static int
1421 handle_recv(combuf)
1422 vchar_t *combuf;
1424 struct admin_com *com;
1425 caddr_t buf;
1426 int len;
1428 com = (struct admin_com *)combuf->v;
1429 len = com->ac_len - sizeof(*com);
1430 buf = combuf->v + sizeof(*com);
1432 switch (com->ac_cmd) {
1433 case ADMIN_SHOW_SCHED:
1434 print_schedule(buf, len);
1435 break;
1437 case ADMIN_SHOW_EVT: {
1438 struct evt_async *ec;
1440 /* We got no event? */
1441 if (len == 0)
1442 break;
1444 if (len < sizeof(struct evt_async))
1445 errx(1, "Short buffer\n");
1447 ec = (struct evt_async *) buf;
1448 if (evt_quit_event <= 0)
1449 print_evt(ec);
1450 else if (evt_quit_event == ec->ec_type) {
1451 switch (ec->ec_type) {
1452 case EVT_PHASE1_MODE_CFG:
1453 print_cfg(ec, len);
1454 break;
1455 default:
1456 print_evt(ec);
1457 break;
1459 evt_quit_event = 0;
1461 break;
1464 case ADMIN_GET_SA_CERT:
1465 fwrite(buf, len, 1, stdout);
1466 break;
1468 case ADMIN_SHOW_SA:
1470 switch (com->ac_proto) {
1471 case ADMIN_PROTO_ISAKMP:
1472 dump_isakmp_sa(buf, len);
1473 break;
1474 case ADMIN_PROTO_IPSEC:
1475 case ADMIN_PROTO_AH:
1476 case ADMIN_PROTO_ESP:
1478 struct sadb_msg *msg = (struct sadb_msg *)buf;
1480 switch (msg->sadb_msg_errno) {
1481 case ENOENT:
1482 switch (msg->sadb_msg_type) {
1483 case SADB_DELETE:
1484 case SADB_GET:
1485 printf("No entry.\n");
1486 break;
1487 case SADB_DUMP:
1488 printf("No SAD entries.\n");
1489 break;
1491 break;
1492 case 0:
1493 while (1) {
1494 pfkey_sadump(msg);
1495 if (msg->sadb_msg_seq == 0)
1496 break;
1497 msg = (struct sadb_msg *)((caddr_t)msg +
1498 PFKEY_UNUNIT64(msg->sadb_msg_len));
1500 break;
1501 default:
1502 printf("%s.\n", strerror(msg->sadb_msg_errno));
1505 break;
1506 case ADMIN_PROTO_INTERNAL:
1507 dump_internal(buf, len);
1508 break;
1509 default:
1510 printf("Invalid proto [%d]\n", com->ac_proto);
1514 break;
1516 default:
1517 /* IGNORE */
1518 break;
1521 return 0;
1523 bad:
1524 return -1;