]> git.saurik.com Git - apple/ipsec.git/blobdiff - ipsec-tools/racoon/racoonctl.c
ipsec-164.10.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / racoonctl.c
index e59b1f90b09cbdac7439462528a3e27135b40485..661f85e1d29d09987ce803e189a425cf6dca7130 100644 (file)
@@ -1,4 +1,6 @@
-/*     $Id: racoonctl.c,v 1.2.2.1 2005/04/21 09:07:20 monas Exp $ */
+/*     $NetBSD: racoonctl.c,v 1.7 2006/10/02 07:12:26 manu Exp $       */
+
+/*     Id: racoonctl.c,v 1.11 2006/04/06 17:06:25 manubsd Exp */
 
 /*
  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
-#ifdef __APPLE__
 #include <System/net/pfkeyv2.h>
-#else
-#include <net/pfkeyv2.h>
-#endif
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -65,6 +63,7 @@
 #endif
 #include <err.h>
 #include <sys/ioctl.h> 
+#include <resolv.h>
 
 #include "var.h"
 #include "vmbuf.h"
@@ -77,6 +76,7 @@
 #include "handler.h"
 #include "sockmisc.h"
 #include "vmbuf.h"
+#include "plog.h"
 #include "isakmp_var.h"
 #include "isakmp.h"
 #include "isakmp_xauth.h"
@@ -97,8 +97,13 @@ static vchar_t *f_flushsa __P((int, char **));
 static vchar_t *f_deletesa __P((int, char **));
 static vchar_t *f_exchangesa __P((int, char **));
 static vchar_t *f_vpnc __P((int, char **));
+static vchar_t *f_exchangesatest __P((int, char **));
+static vchar_t *f_vpntest __P((int, char **));
 static vchar_t *f_vpnd __P((int, char **));
 static vchar_t *f_getevt __P((int, char **));
+#ifdef ENABLE_HYBRID
+static vchar_t *f_logoutusr __P((int, char **));
+#endif
 
 struct cmd_tag {
        vchar_t *(*func) __P((int, char **));
@@ -119,10 +124,15 @@ struct cmd_tag {
        { f_exchangesa, ADMIN_ESTABLISH_SA,     "es" },
        { f_vpnc,       ADMIN_ESTABLISH_SA,     "vpn-connect" },
        { f_vpnc,       ADMIN_ESTABLISH_SA,     "vc" },
+       { f_vpntest, ADMIN_ESTABLISH_SA_VPNCONTROL, "vpntest" },
        { f_vpnd,       ADMIN_DELETE_ALL_SA_DST,"vpn-disconnect" },
        { f_vpnd,       ADMIN_DELETE_ALL_SA_DST,"vd" },
        { f_getevt,     ADMIN_SHOW_EVT,         "show-event" },
        { f_getevt,     ADMIN_SHOW_EVT,         "se" },
+#ifdef ENABLE_HYBRID
+       { f_logoutusr,  ADMIN_LOGOUT_USER,      "logout-user" },
+       { f_logoutusr,  ADMIN_LOGOUT_USER,      "lu" },
+#endif
        { NULL, 0, NULL },
 };
 
@@ -145,7 +155,10 @@ struct evtmsg {
        { EVTT_XAUTH_FAILED, "Xauth exchange failed", ERROR },
        { EVTT_PEERPH1AUTH_FAILED, "Peer failed phase 1 authentication "
            "(certificate problem?)", ERROR },
+       { EVTT_PEERPH1_NOPROP, "Peer failed phase 1 initiation "
+           "(proposal problem?)", ERROR },
        { 0, NULL, UNSPEC },
+       { EVTT_NO_ISAKMP_CFG, "No need for ISAKMP mode config ", INFO },
 };
 
 static int get_proto __P((char *));
@@ -207,6 +220,7 @@ void print_evt __P((caddr_t, int));
 void print_cfg __P((caddr_t, int));
 void print_err __P((caddr_t, int));
 void print_ph1down __P((caddr_t, int));
+void print_ph1up __P((caddr_t, int));
 int evt_poll __P((void));
 char * fixed_addr __P((char *, char *, int));
 
@@ -258,13 +272,6 @@ main(ac, av)
            (racoonctl_interface < RACOONCTL_INTERFACE))
                errx(1, "Incompatible racoonctl interface");
 
-#ifdef __linux__
-       /*
-        * Disable GNU extensions that will prevent racoonct vc -u login
-        * from working (GNU getopt(3) does not like options after vc)
-        */
-       setenv("POSIXLY_CORRECT", "1", 0);
-#endif
        while ((c = getopt(ac, av, "lds:")) != -1) {
                switch(c) {
                case 'l':
@@ -329,6 +336,7 @@ evt_poll(void) {
                errx(1, "Cannot make combuf");
 
        while (evt_filter & (EVTF_LOOP|EVTF_PURGE)) {
+               /* handle_recv closes the socket time, so open it each time */
                com_init();
                if (com_send(sendbuf) != 0)
                        errx(1, "Cannot send combuf");
@@ -343,7 +351,7 @@ evt_poll(void) {
                (void)select(0, NULL, NULL, NULL, &tv);
        }
 
-       /* NOTREACHED */
+       vfree(sendbuf);
        return 0;
 }
 
@@ -555,7 +563,7 @@ f_deletesa(ac, av)
 
        buf = vmalloc(sizeof(*head) + index->l);
        if (buf == NULL)
-               return NULL;
+               goto out;
 
        head = (struct admin_com *)buf->v;
        head->ac_len = buf->l + index->l;
@@ -565,6 +573,10 @@ f_deletesa(ac, av)
 
        memcpy(buf->v+sizeof(*head), index->v, index->l);
 
+out:
+       if (index != NULL)
+               vfree(index);
+
        return buf;
 }
 
@@ -606,7 +618,7 @@ f_deleteallsadst(ac, av)
 
        buf = vmalloc(sizeof(*head) + index->l);
        if (buf == NULL)
-               return NULL;
+               goto out;
 
        head = (struct admin_com *)buf->v;
        head->ac_len = buf->l + index->l;
@@ -616,6 +628,10 @@ f_deleteallsadst(ac, av)
 
        memcpy(buf->v+sizeof(*head), index->v, index->l);
 
+out:
+       if (index != NULL)
+               vfree(index);
+
        return buf;
 }
 
@@ -691,21 +707,123 @@ f_exchangesa(ac, av)
        memcpy(buf->v+sizeof(*head), index->v, index->l);
 
        if (id && key) {
+               // overload com_len to track the number of unused bytes in buf->v
                char *data;
                acp = (struct admin_com_psk *)
                    (buf->v + sizeof(*head) + index->l);
+               com_len -= sizeof(*head) + index->l;
 
-               acp->id_type = IDTYPE_LOGIN;
+               acp->id_type = IDTYPE_USERFQDN;
                acp->id_len = strlen(id) + 1;
                acp->key_len = strlen(key) + 1;
 
                data = (char *)(acp + 1);
-               strcpy(data, id);
+               com_len -= sizeof(*acp);
+               strlcpy(data, id, com_len);
 
                data = (char *)(data + acp->id_len);
-               strcpy(data, key);
+               com_len -= acp->id_len;
+               strlcpy(data, key, com_len);
        }
 
+       vfree(index);
+
+       return buf;
+}
+
+// %%%%% testing
+static vchar_t *
+f_exchangesatest(ac, av)
+       int ac;
+       char **av;
+{
+       vchar_t *buf, *index;
+       struct admin_com *head;
+       int proto;
+       int cmd = ADMIN_ESTABLISH_SA_VPNCONTROL;
+       size_t com_len = 0;
+       char *id = NULL;
+       char *key = NULL;
+       struct admin_com_psk *acp;
+
+       if (ac < 1)
+               errx(1, "insufficient arguments");
+
+       /* Optional -u identity */
+       if (strcmp(av[0], "-u") == 0) {
+               if (ac < 2)
+                       errx(1, "-u require an argument");
+
+               id = av[1];
+               if ((key = getpass("Password: ")) == NULL)
+                       errx(1, "getpass() failed: %s", strerror(errno));
+               
+               com_len += sizeof(*acp) + strlen(id) + 1 + strlen(key) + 1;
+               cmd = ADMIN_ESTABLISH_SA_VPNCONTROL;
+
+               av += 2;
+               ac -= 2;
+       }
+
+       /* need protocol */
+       if (ac < 1)
+               errx(1, "insufficient arguments");
+       if ((proto = get_proto(*av)) == -1)
+               errx(1, "unknown protocol %s", *av);
+
+       /* get index(es) */
+       av++;
+       ac--;
+       switch (proto) {
+       case ADMIN_PROTO_ISAKMP:
+               index = get_index(ac, av);
+               if (index == NULL)
+                       return NULL;
+               break;
+       case ADMIN_PROTO_AH:
+       case ADMIN_PROTO_ESP:
+               index = get_index(ac, av);
+               if (index == NULL)
+                       return NULL;
+               break;
+       default:
+               errno = EPROTONOSUPPORT;
+               return NULL;
+       }
+
+       com_len += sizeof(*head) + index->l;
+       if ((buf = vmalloc(com_len)) == NULL)
+               errx(1, "Cannot allocate buffer");
+
+       head = (struct admin_com *)buf->v;
+       head->ac_len = buf->l;
+       head->ac_cmd = cmd;
+       head->ac_errno = 0;
+       head->ac_proto = proto;
+
+       memcpy(buf->v+sizeof(*head), index->v, index->l);
+
+       if (id && key) {
+               // overload com_len to track the number of unused bytes in buf->v
+               char *data;
+               acp = (struct admin_com_psk *)
+                   (buf->v + sizeof(*head) + index->l);
+               com_len -= sizeof(*head) + index->l;
+
+               acp->id_type = IDTYPE_USERFQDN;
+               acp->id_len = strlen(id) + 1;
+               acp->key_len = strlen(key) + 1;
+
+               data = (char *)(acp + 1);
+               strlcpy(data, id, com_len);
+
+               data = (char *)(data + acp->id_len);
+               com_len -= acp->id_len;
+               strlcpy(data, key, com_len);
+       }
+
+       vfree(index);
+
        return buf;
 }
 
@@ -720,7 +838,73 @@ f_vpnc(ac, av)
        char *inet = "inet";
        char *srcaddr;
        struct addrinfo hints, *res;
-       struct sockaddr *src;
+       struct sockaddr_storage *src;
+       char *idx;
+
+       if (ac < 1)
+               errx(1, "insufficient arguments");
+
+       evt_filter = (EVTF_LOOP|EVTF_CFG|EVTF_CFG_STOP|EVTF_ERR|EVTF_ERR_STOP);
+       time(&evt_start);
+       
+       /* Optional -u identity */
+       if (strcmp(av[0], "-u") == 0) {
+               if (ac < 2)
+                       errx(1, "-u require an argument");
+
+               nav[nac++] = av[0];
+               nav[nac++] = av[1];
+
+               ac -= 2;
+               av += 2;
+       }
+
+       if (ac < 1)
+               errx(1, "VPN gateway required");        
+       if (ac > 1)
+               warnx("Extra arguments");
+
+       /*
+        * Find the source address
+        */
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_socktype = SOCK_DGRAM;
+       if (getaddrinfo(av[0], "4500", &hints, &res) != 0)
+               errx(1, "Cannot resolve destination address");
+
+       if ((src = getlocaladdr(res->ai_addr)) == NULL)
+               errx(1, "cannot find source address");
+
+       if ((srcaddr = saddr2str(src)) == NULL)
+               errx(1, "cannot read source address");
+
+       /* We get "ip[port]" strip the port */
+       if ((idx = index(srcaddr, '[')) == NULL) 
+               errx(1, "unexpected source address format");
+       *idx = '\0';
+
+       nav[nac++] = isakmp;
+       nav[nac++] = inet;
+       nav[nac++] = srcaddr;
+       nav[nac++] = av[0];
+
+       return f_exchangesa(nac, nav);
+}
+
+// %%% testing
+static vchar_t *
+f_vpntest(ac, av)
+       int ac;
+       char **av;
+{
+       char *nav[] = {NULL, NULL, NULL, NULL, NULL, NULL};
+       int nac = 0;
+       char *isakmp = "isakmp";
+       char *inet = "inet";
+       char *srcaddr;
+       struct addrinfo hints, *res;
+       struct sockaddr_storage *src;
        char *idx;
 
        if (ac < 1)
@@ -785,7 +969,6 @@ f_vpnd(ac, av)
        char *inet = "inet";
        char *anyaddr = "0.0.0.0";
        char *idx;
-       vchar_t *buf, *index;
 
        if (ac < 1)
                errx(1, "VPN gateway required");        
@@ -803,6 +986,39 @@ f_vpnd(ac, av)
        return f_deleteallsadst(nac, nav);
 }
 
+#ifdef ENABLE_HYBRID
+static vchar_t *
+f_logoutusr(ac, av)
+       int ac;
+       char **av;
+{
+       vchar_t *buf;
+       struct admin_com *head;
+       char *user;
+
+       /* need username */
+       if (ac < 1)
+               errx(1, "insufficient arguments");
+       user = av[0];
+       if ((user == NULL) || ((strlen(user) + 1) > LOGINLEN))
+               errx(1, "bad login (too long?)");
+
+       buf = vmalloc(sizeof(*head) + LOGINLEN);
+       if (buf == NULL)
+               return NULL;
+
+       head = (struct admin_com *)buf->v;
+       head->ac_len = buf->l;
+       head->ac_cmd = ADMIN_LOGOUT_USER;
+       head->ac_errno = 0;
+       head->ac_proto = 0;
+
+       strlcpy((char *)(head + 1), user, LOGINLEN);
+
+       return buf;
+}
+#endif /* ENABLE_HYBRID */
+
 
 static int
 get_proto(str)
@@ -871,7 +1087,7 @@ get_comindexes(family, ac, av)
        struct admin_com_indexes *ci;
        char *p_name = NULL, *p_port = NULL;
        char *p_prefs = NULL, *p_prefd = NULL;
-       struct sockaddr *src = NULL, *dst = NULL;
+       struct sockaddr_storage *src = NULL, *dst = NULL;
        int ulproto;
 
        if (ac != 2 && ac != 3) {
@@ -959,28 +1175,34 @@ get_comindex(str, name, port, pref)
 
        *name = *port = *pref = NULL;
 
-       *name = strdup(str);
+       *name = racoon_strdup(str);
+       STRDUP_FATAL(*name);
        p = strpbrk(*name, "/[");
        if (p != NULL) {
                if (*(p + 1) == '\0')
                        goto bad;
                if (*p == '/') {
                        *p = '\0';
-                       *pref = strdup(p + 1);
+                       *pref = racoon_strdup(p + 1);
+                       STRDUP_FATAL(*pref);
                        p = strchr(*pref, '[');
                        if (p != NULL) {
                                if (*(p + 1) == '\0')
                                        goto bad;
                                *p = '\0';
-                               *port = strdup(p + 1);
+                               *port = racoon_strdup(p + 1);
+                               STRDUP_FATAL(*port);
                                p = strchr(*pref, ']');
                                if (p == NULL)
                                        goto bad;
                                *p = '\0';
                        }
                } else if (*p == '[') {
+                       if (*pref == NULL)
+                               goto bad;
                        *p = '\0';
-                       *port = strdup(p + 1);
+                       *port = racoon_strdup(p + 1);
+                       STRDUP_FATAL(*port);
                        p = strchr(*pref, ']');
                        if (p == NULL)
                                goto bad;
@@ -1085,7 +1307,7 @@ char *header3 =
        while (len-- > 0) {
                /* source address */
                if (long_format >= 2) {
-                       GETNAMEINFO((struct sockaddr *)&pd->local, _addr1_, _addr2_);
+                       GETNAMEINFO((struct sockaddr_storage *)&pd->local, _addr1_, _addr2_);
                        switch (long_format) {
                        case 0:
                                break;
@@ -1101,7 +1323,7 @@ char *header3 =
                }
 
                /* destination address */
-               GETNAMEINFO((struct sockaddr *)&pd->remote, _addr1_, _addr2_);
+               GETNAMEINFO((struct sockaddr_storage *)&pd->remote, _addr1_, _addr2_);
                switch (long_format) {
                case 0:
                case 1:
@@ -1153,7 +1375,7 @@ dump_internal(buf, tlen)
        int tlen;
 {
        struct ph2handle *iph2;
-       struct sockaddr *addr;
+       struct sockaddr_storage *addr;
 
 /*
 short header;
@@ -1176,7 +1398,7 @@ char *long_h1 =
 
        while (tlen > 0) {
                iph2 = (struct ph2handle *)buf;
-               addr = (struct sockaddr *)(++iph2);
+               addr = (struct sockaddr_storage *)(++iph2);
 
                GETNAMEINFO(addr, _addr1_, _addr2_);
                printf("%s ", long_format ?
@@ -1292,12 +1514,12 @@ print_evt(buf, len)
        else
                printf("%s : ", evtmsg[i].msg);
 
-       if ((srcstr = saddr2str((struct sockaddr *)&evtdump->src)) == NULL)
+       if ((srcstr = saddr2str((struct sockaddr_storage *)&evtdump->src)) == NULL)
                printf("unknown");
        else 
                printf("%s", srcstr);
        printf(" -> ");
-       if ((dststr = saddr2str((struct sockaddr *)&evtdump->dst)) == NULL)
+       if ((dststr = saddr2str((struct sockaddr_storage *)&evtdump->dst)) == NULL)
                printf("unknown");
        else 
                printf("%s", dststr);
@@ -1369,7 +1591,8 @@ print_cfg(buf, len)
        
        memset(&addr4, 0, sizeof(addr4));
 
-       if (evtdump->type != EVTT_ISAKMP_CFG_DONE)
+       if (evtdump->type != EVTT_ISAKMP_CFG_DONE && 
+           evtdump->type != EVTT_NO_ISAKMP_CFG)
                return;
 
        len -= sizeof(*evtdump);
@@ -1422,8 +1645,12 @@ print_cfg(buf, len)
                            (n + sizeof(*attr) + ntohs(attr->lorv));
                }
        }
-
-       printf("Bound to address %s\n", inet_ntoa(addr4));
+       
+       if (evtdump->type == EVTT_ISAKMP_CFG_DONE)
+               printf("Bound to address %s\n", inet_ntoa(addr4));
+       else
+               printf("VPN connexion established\n");
+       
        if (banner) {
                struct winsize win;
                int col = 0;
@@ -1438,6 +1665,7 @@ print_cfg(buf, len)
                for (i = 0; i < col; i++)
                        printf("%c", '=');
                printf("\n");
+               racoon_free(banner);
        }
        
        if (evt_filter & EVTF_CFG_STOP)