added XAUTH server and client support
authorAndreas Steffen <andreas.steffen@strongswan.org>
Thu, 4 Jan 2007 14:28:57 +0000 (14:28 -0000)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Thu, 4 Jan 2007 14:28:57 +0000 (14:28 -0000)
13 files changed:
src/pluto/connections.c
src/pluto/constants.c
src/pluto/constants.h
src/pluto/demux.c
src/pluto/ipsec_doi.c
src/pluto/keys.c
src/pluto/keys.h
src/pluto/modecfg.c
src/pluto/modecfg.h
src/pluto/state.h
src/pluto/vendor.c
src/pluto/xauth.c [new file with mode: 0644]
src/pluto/xauth.h [new file with mode: 0644]

index eb15701..0d02b97 100644 (file)
@@ -3333,6 +3333,9 @@ refine_host_connection(const struct state *st, const struct id *peer_id
     case XAUTHInitPreShared:
     case XAUTHRespPreShared:
        auth_policy = POLICY_XAUTH_PSK;
+       psk = get_preshared_secret(c);
+       if (psk == NULL)
+           return NULL;        /* cannot determine PSK! */
        break;
     case OAKLEY_RSA_SIG:
        auth_policy = POLICY_RSASIG;
index 883f82e..ed8073b 100644 (file)
@@ -54,8 +54,8 @@ const char compile_time_interop_options[] = ""
 #ifdef VENDORID
        " VENDORID"
 #endif
-#ifdef XAUTH_VID
-       " XAUTH_VID"
+#ifdef CISCO_QUIRKS
+       " CISCO_QUIRKS"
 #endif
 #ifdef USE_KEYRR
        " KEYRR"
@@ -183,19 +183,22 @@ static const char *const state_name[] = {
        "STATE_INFO",
        "STATE_INFO_PROTECTED",
 
-       "STATE_XAUTH_R1",
-       "STATE_XAUTH_R2",
-       "STATE_XAUTH_R3",
        "STATE_XAUTH_I0",
+       "STATE_XAUTH_R1",
        "STATE_XAUTH_I1",
+       "STATE_XAUTH_R2",
        "STATE_XAUTH_I2",
+       "STATE_XAUTH_R3",
 
        "STATE_MODE_CFG_R0",
-       "STATE_MODE_CFG_R1",
-       "STATE_MODE_CFG_R2",
        "STATE_MODE_CFG_I1",
+       "STATE_MODE_CFG_R1",
        "STATE_MODE_CFG_I2",
+
+       "STATE_MODE_CFG_I0",
+       "STATE_MODE_CFG_R3",
        "STATE_MODE_CFG_I3",
+       "STATE_MODE_CFG_R4",
 
        "STATE_IKE_ROOF"
     };
@@ -224,19 +227,22 @@ const char *const state_story[] = {
        "got Informational Message in clear",    /* STATE_INFO */
        "got encrypted Informational Message",   /* STATE_INFO_PROTECTED */
 
-       "sent XAUTH request, expecting reply",   /* STATE_XAUTH_R1 */
-       "sent XAUTH status, expecting ack",      /* STATE_XAUTH_R2 */
-       "received XAUTH ack, established",       /* STATE_XAUTH_R3 */
        "expecting XAUTH request",               /* STATE_XAUTH_I0 */
+       "sent XAUTH request, expecting reply",   /* STATE_XAUTH_R1 */
        "sent XAUTH reply, expecting status",    /* STATE_XAUTH_I1 */
+       "sent XAUTH status, expecting ack",      /* STATE_XAUTH_R2 */
        "sent XAUTH ack, established",           /* STATE_XAUTH_I2 */
+       "received XAUTH ack, established",       /* STATE_XAUTH_R3 */
 
        "expecting ModeCfg request",             /* STATE_MODE_CFG_R0 */
-       "sent ModeCfg reply, expecting ack",     /* STATE_MODE_CFG_R1 */
-       "received ModeCfg ack, established"      /* STATE_MODE_CFG_R2 */
        "sent ModeCfg request, expecting reply", /* STATE_MODE_CFG_I1 */
-       "sent ModeCfg ack, established",         /* STATE_MODE_CFG_I2 */
-       "received ModeCfg set, sent ack",        /* STATE_MODE_CFG_I3 */
+       "sent ModeCfg reply, established",       /* STATE_MODE_CFG_R1 */
+       "received ModeCfg reply, established",   /* STATE_MODE_CFG_I2 */
+
+       "expecting ModeCfg set",                 /* STATE_MODE_CFG_I0 */
+       "sent ModeCfg set, expecting ack",       /* STATE_MODE_CFG_R3 */
+       "sent ModeCfg ack, established",         /* STATE_MODE_CFG_I3 */
+       "received ModeCfg ack, established",     /* STATE_MODE_CFG_R4 */
     };
 
 /* kind of struct connection */
index 57e9cf9..7d99ce2 100644 (file)
@@ -508,23 +508,27 @@ enum state_kind {
 
     /* XAUTH states */
 
-    STATE_XAUTH_R1,              /* responder states (server) */
+    STATE_XAUTH_I0,              /* initiator state (client) */
+    STATE_XAUTH_R1,              /* responder state (server) */
+    STATE_XAUTH_I1,
     STATE_XAUTH_R2,
+    STATE_XAUTH_I2,
     STATE_XAUTH_R3,
 
-    STATE_XAUTH_I0,              /* initiator states (client) */
-    STATE_XAUTH_I1,
-    STATE_XAUTH_I2,
 
-    /* Mode Config states */
+    /* Mode Config pull states */
 
-    STATE_MODE_CFG_R0,           /* responder states */
+    STATE_MODE_CFG_R0,           /* responder state (server) */
+    STATE_MODE_CFG_I1,           /* initiator state (client) */
     STATE_MODE_CFG_R1,
-    STATE_MODE_CFG_R2,
-
-    STATE_MODE_CFG_I1,           /* initiator states */
     STATE_MODE_CFG_I2,
+
+    /* Mode Config push states */
+
+    STATE_MODE_CFG_I0,           /* initiator state (client) */
+    STATE_MODE_CFG_R3,           /* responder state (server) */
     STATE_MODE_CFG_I3,
+    STATE_MODE_CFG_R4,
 
     STATE_IKE_ROOF
 };
@@ -537,26 +541,26 @@ enum state_kind {
       LELEM(STATE_MAIN_R3)     | LELEM(STATE_MAIN_I4)     \
     | LELEM(STATE_XAUTH_R1)    | LELEM(STATE_XAUTH_R2) | LELEM(STATE_XAUTH_R3) \
     | LELEM(STATE_XAUTH_I1)    | LELEM(STATE_XAUTH_I2)    \
-    | LELEM(STATE_MODE_CFG_R1) | LELEM(STATE_MODE_CFG_R2) \
-    | LELEM(STATE_MODE_CFG_I2) | LELEM(STATE_MODE_CFG_I3))
+    | LELEM(STATE_MODE_CFG_I1) | LELEM(STATE_MODE_CFG_R1) | LELEM(STATE_MODE_CFG_I2) \
+    | LELEM(STATE_MODE_CFG_R3) | LELEM(STATE_MODE_CFG_I3) | LELEM(STATE_MODE_CFG_R4))
 
 #define IS_PHASE1(s) ((STATE_MAIN_R0 <= (s) && (s) <= STATE_MAIN_I4) \
-                  || (STATE_XAUTH_R1 <= (s) && (s) <= STATE_XAUTH_I2) \
-                  || (STATE_MODE_CFG_R0 <= (s) && (s) <= STATE_MODE_CFG_I3))
+                  || (STATE_XAUTH_I0 <= (s) && (s) <= STATE_XAUTH_R3) \
+                  || (STATE_MODE_CFG_R0 <= (s) && (s) <= STATE_MODE_CFG_R4))
+
 #define IS_QUICK(s) (STATE_QUICK_R0 <= (s) && (s) <= STATE_QUICK_R2)
 #define IS_ISAKMP_ENCRYPTED(s) (STATE_MAIN_I2 <= (s))
-#define IS_ISAKMP_SA_ESTABLISHED(s) (         \
-                                    (s) == STATE_MAIN_R3     \
-                                 || (s) == STATE_MAIN_I4     \
-                                 || (s) == STATE_XAUTH_R1    \
-                                 || (s) == STATE_XAUTH_R2    \
-                                 || (s) == STATE_XAUTH_R3    \
-                                 || (s) == STATE_XAUTH_I1    \
-                                 || (s) == STATE_XAUTH_I2    \
-                                 || (s) == STATE_MODE_CFG_R1 \
-                                 || (s) == STATE_MODE_CFG_R2 \
-                                 || (s) == STATE_MODE_CFG_I2 \
-                                 || (s) == STATE_MODE_CFG_I3)
+
+#define IS_ISAKMP_SA_ESTABLISHED(s) (        \
+                  (s) == STATE_MAIN_R3      \
+               || (s) == STATE_MAIN_I4      \
+               || (s) == STATE_XAUTH_R3     \
+               || (s) == STATE_XAUTH_I2     \
+               || (s) == STATE_MODE_CFG_R1  \
+               || (s) == STATE_MODE_CFG_I2  \
+               || (s) == STATE_MODE_CFG_I3  \
+               || (s) == STATE_MODE_CFG_R4)
+
 #define IS_IPSEC_SA_ESTABLISHED(s) ((s) == STATE_QUICK_I2 || (s) == STATE_QUICK_R2)
 #define IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(s) ((s) == STATE_QUICK_R1)
 
index 564988c..1f47daf 100644 (file)
@@ -436,77 +436,81 @@ static const struct state_microcode state_microcode_table[] = {
     , P(HASH), LEMPTY, PT(NONE)
     , EVENT_NULL, informational },
 
-    /* XAUTH server */
+    /* XAUTH state transitions */
+    { STATE_XAUTH_I0, STATE_XAUTH_I1
+    , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY
+    , P(ATTR) | P(HASH), P(VID), PT(HASH)
+    , EVENT_RETRANSMIT, xauth_inI0 },
+
     { STATE_XAUTH_R1, STATE_XAUTH_R2
     , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY
     , P(ATTR) | P(HASH), P(VID), PT(HASH)
     , EVENT_RETRANSMIT, xauth_inR1 },
 
+    { STATE_XAUTH_I1, STATE_XAUTH_I2
+    , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2
+    , P(ATTR) | P(HASH), P(VID), PT(HASH)
+    , EVENT_SA_REPLACE, xauth_inI1 },
+
     { STATE_XAUTH_R2, STATE_XAUTH_R3
     , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2
     , P(ATTR) | P(HASH), P(VID), PT(NONE)
     , EVENT_SA_REPLACE, xauth_inR2 },
 
-    { STATE_XAUTH_R3, STATE_UNDEFINED
+    { STATE_XAUTH_I2, STATE_UNDEFINED
     , SMF_ALL_AUTH | SMF_ENCRYPTED
     , LEMPTY, LEMPTY, PT(NONE)
     , EVENT_NULL, unexpected },
 
-    /* XAUTH client */
-    { STATE_XAUTH_I0, STATE_XAUTH_I1
-    , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY
-    , P(ATTR) | P(HASH), P(VID), PT(HASH)
-    , EVENT_SA_REPLACE, xauth_inI0 },
-
-    { STATE_XAUTH_I1, STATE_XAUTH_I2
-    , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2
-    , P(ATTR) | P(HASH), P(VID), PT(HASH)
-    , EVENT_SA_REPLACE, xauth_inI1 },
-
-    { STATE_XAUTH_I2, STATE_UNDEFINED
+    { STATE_XAUTH_R3, STATE_UNDEFINED
     , SMF_ALL_AUTH | SMF_ENCRYPTED
     , LEMPTY, LEMPTY, PT(NONE)
     , EVENT_NULL, unexpected },
 
-    /* MODE_CFG_x:
-     * Case R0:  Responder  -> Initiator
-     *                    <-   Req(addr=0)
-     *     Reply(ad=x)     ->
-     *
-     * Case R1: Set(addr=x) ->
-     *                    <-   Ack(ok)
-     */
+    /* ModeCfg pull mode state transitions */
 
     { STATE_MODE_CFG_R0, STATE_MODE_CFG_R1
-    , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY
+    , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2
     , P(ATTR) | P(HASH), P(VID), PT(HASH)
     , EVENT_SA_REPLACE, modecfg_inR0 },
 
-    { STATE_MODE_CFG_R1, STATE_MODE_CFG_R2
-    , SMF_ALL_AUTH | SMF_ENCRYPTED
+    { STATE_MODE_CFG_I1, STATE_MODE_CFG_I2
+    , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2
     , P(ATTR) | P(HASH), P(VID), PT(HASH)
-    , EVENT_SA_REPLACE, modecfg_inR1 },
+    , EVENT_SA_REPLACE, modecfg_inI1 },
 
-    { STATE_MODE_CFG_R2, STATE_UNDEFINED
+    { STATE_MODE_CFG_R1, STATE_UNDEFINED
     , SMF_ALL_AUTH | SMF_ENCRYPTED
     , LEMPTY, LEMPTY, PT(NONE)
     , EVENT_NULL, unexpected },
 
-    { STATE_MODE_CFG_I1, STATE_MODE_CFG_I2
-    , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2
-    , P(ATTR) | P(HASH), P(VID), PT(HASH)
-    , EVENT_SA_REPLACE, modecfg_inI1 },
+    { STATE_MODE_CFG_I2, STATE_UNDEFINED
+    , SMF_ALL_AUTH | SMF_ENCRYPTED
+    , LEMPTY, LEMPTY, PT(NONE)
+    , EVENT_NULL, unexpected },
+
+   /* ModeCfg push mode state transitions */
 
-    { STATE_MODE_CFG_I2, STATE_MODE_CFG_I3
+    { STATE_MODE_CFG_I0, STATE_MODE_CFG_I3
     , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2
     , P(ATTR) | P(HASH), P(VID), PT(HASH)
-    , EVENT_SA_REPLACE, modecfg_inI2 },
+    , EVENT_SA_REPLACE, modecfg_inI0 },
+
+    { STATE_MODE_CFG_R3, STATE_MODE_CFG_R4
+    , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2
+    , P(ATTR) | P(HASH), P(VID), PT(HASH)
+    , EVENT_SA_REPLACE, modecfg_inR3 },
 
     { STATE_MODE_CFG_I3, STATE_UNDEFINED
     , SMF_ALL_AUTH | SMF_ENCRYPTED
     , LEMPTY, LEMPTY, PT(NONE)
     , EVENT_NULL, unexpected },
 
+    { STATE_MODE_CFG_R4, STATE_UNDEFINED
+    , SMF_ALL_AUTH | SMF_ENCRYPTED
+    , LEMPTY, LEMPTY, PT(NONE)
+    , EVENT_NULL, unexpected },
+
 #undef P
 #undef PT
 };
@@ -1464,11 +1468,6 @@ process_packet(struct msg_digest **mdp)
                return;
            }
 
-           if (st->st_state == STATE_MODE_CFG_R2)   /* Have we just give an IP address to peer? */
-           {
-               st->st_state = STATE_MAIN_R3;       /* ISAKMP is up... */
-           }
-
            set_cur_state(st);
 
            if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state))
@@ -1588,7 +1587,7 @@ process_packet(struct msg_digest **mdp)
                               & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK))
                               != LEMPTY;
 
-           if (has_xauth_policy
+           if (has_xauth_policy && !st->st_xauth.started
            && IS_PHASE1(st->st_state))
            {
                from_state = STATE_XAUTH_I0;
@@ -1601,7 +1600,7 @@ process_packet(struct msg_digest **mdp)
            else if (st->st_connection->spd.this.modecfg
            && IS_PHASE1(st->st_state))
            {
-               from_state = STATE_MODE_CFG_I2;
+               from_state = STATE_MODE_CFG_I0;
            }
            else
            {
@@ -1616,7 +1615,6 @@ process_packet(struct msg_digest **mdp)
            set_cur_state(st);
            from_state = st->st_state;
        }
-
        break;
 
 #ifdef NOTYET
@@ -2358,7 +2356,7 @@ complete_state_transition(struct msg_digest **mdp, stf_status result)
                }
 
                if (IS_ISAKMP_SA_ESTABLISHED(st->st_state)
-               || IS_IPSEC_SA_ESTABLISHED(st->st_state))
+               ||  IS_IPSEC_SA_ESTABLISHED(st->st_state))
                {
                    /* log our success */
                    plog("%s%s", story, sadetails);
@@ -2391,6 +2389,17 @@ complete_state_transition(struct msg_digest **mdp, stf_status result)
                break;
            }
 
+           /* Wait for XAUTH request from server */
+           if (has_xauth_policy && !is_xauth_server
+           && IS_ISAKMP_SA_ESTABLISHED(st->st_state)
+           && !st->st_xauth.started)
+           {
+               DBG(DBG_CONTROL,
+                   DBG_log("waiting for XAUTH request from server")
+               )
+               break;
+           }
+
            /* Should we start ModeConfig as a client? */
            if (st->st_connection->spd.this.modecfg
            && IS_ISAKMP_SA_ESTABLISHED(st->st_state)
@@ -2417,17 +2426,6 @@ complete_state_transition(struct msg_digest **mdp, stf_status result)
                break;
            }
 
-           /* Wait for XAUTH request from server */
-           if (has_xauth_policy && !is_xauth_server
-           && IS_ISAKMP_SA_ESTABLISHED(st->st_state)
-           && !st->st_xauth.started)
-           {
-               DBG(DBG_CONTROL,
-                   DBG_log("waiting for XAUTH request from server")
-               )
-               break;
-           }
-
            /* Wait for ModeConfig set from server */
            if (st->st_connection->spd.this.modecfg
            && IS_ISAKMP_SA_ESTABLISHED(st->st_state)
@@ -2453,7 +2451,7 @@ complete_state_transition(struct msg_digest **mdp, stf_status result)
            }
 
            if (IS_ISAKMP_SA_ESTABLISHED(st->st_state)
-           || IS_IPSEC_SA_ESTABLISHED(st->st_state))
+           ||  IS_IPSEC_SA_ESTABLISHED(st->st_state))
                release_whack(st);
            break;
 
index 9d53a1a..f35b5f9 100644 (file)
 #endif /* !VENDORID */
 
 /*
- * are we sending an XAUTH VID (Cisco Mode Config Interoperability)?
- */
-#ifdef XAUTH_VID
-#define SEND_XAUTH_VID 1
-#else /* !XAUTH_VID */
-#define SEND_XAUTH_VID 0
-#endif /* !XAUTH_VID */
-
-/*
  * are we sending a Cisco Unity VID?
  */
 #ifdef CISCO_QUIRKS
@@ -900,12 +891,12 @@ main_outI1(int whack_sock, struct connection *c, struct state *predecessor
     /* determine how many Vendor ID payloads we will be sending */
     if (SEND_PLUTO_VID)
        vids_to_send++;
-    if (SEND_XAUTH_VID)
-       vids_to_send++;
     if (SEND_CISCO_UNITY_VID)
        vids_to_send++;
     if (c->spd.this.cert.type == CERT_PGP)
        vids_to_send++;
+    /* always send XAUTH Vendor ID */
+       vids_to_send++;
     /* always send DPD Vendor ID */
        vids_to_send++;
     if (nat_traversal_enabled)
@@ -974,17 +965,6 @@ main_outI1(int whack_sock, struct connection *c, struct state *predecessor
        }
     }
 
-    /* if enabled send XAUTH Vendor ID */
-    if (SEND_XAUTH_VID)
-    {
-       if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
-       , &rbody, VID_MISC_XAUTH))
-       {
-           reset_cur_state();
-           return STF_INTERNAL_ERROR;
-       }
-    }
-
     /* if enabled send Cisco Unity Vendor ID */
     if (SEND_CISCO_UNITY_VID)
     {
@@ -1008,6 +988,14 @@ main_outI1(int whack_sock, struct connection *c, struct state *predecessor
        }
     }
 
+    /* Announce our ability to do eXtended AUTHentication to the peer */
+    if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+    , &rbody, VID_MISC_XAUTH))
+    {
+       reset_cur_state();
+       return STF_INTERNAL_ERROR;
+    }
+
     /* Announce our ability to do Dead Peer Detection to the peer */
     {
        if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
@@ -3118,12 +3106,12 @@ main_inI1_outR1(struct msg_digest *md)
     /* determine how many Vendor ID payloads we will be sending */
     if (SEND_PLUTO_VID)
        vids_to_send++;
-    if (SEND_XAUTH_VID)
-       vids_to_send++;
     if (SEND_CISCO_UNITY_VID)
        vids_to_send++;
     if (md->openpgp)
        vids_to_send++;
+    /* always send XAUTH Vendor ID */
+       vids_to_send++;
     /* always send DPD Vendor ID */
        vids_to_send++;
     if (md->nat_traversal_vid && nat_traversal_enabled)
@@ -3167,16 +3155,6 @@ main_inI1_outR1(struct msg_digest *md)
        }
     }
 
-    /* if enabled send XAUTH Vendor ID */
-    if (SEND_XAUTH_VID)
-    {
-       if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
-       , &md->rbody, VID_MISC_XAUTH))
-       {
-           return STF_INTERNAL_ERROR;
-       }
-    }
-
     /* if enabled send Cisco Unity Vendor ID */
     if (SEND_CISCO_UNITY_VID)
     {
@@ -3199,13 +3177,18 @@ main_inI1_outR1(struct msg_digest *md)
        }
     }
 
+    /* Announce our ability to do eXtended AUTHentication to the peer */
+    if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+    , &md->rbody, VID_MISC_XAUTH))
+    {
+       return STF_INTERNAL_ERROR;
+    }
+
     /* Announce our ability to do Dead Peer Detection to the peer */
+    if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
+    , &md->rbody, VID_MISC_DPD))
     {
-       if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE
-       , &md->rbody, VID_MISC_DPD))
-       {
-           return STF_INTERNAL_ERROR;
-       }
+       return STF_INTERNAL_ERROR;
     }
 
     if (md->nat_traversal_vid && nat_traversal_enabled)
@@ -3486,8 +3469,6 @@ main_inR2_outI3(struct msg_digest *md)
 {
     struct state *const st = md->st;
     pb_stream *const keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs;
-    int auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY
-       ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG;
     pb_stream id_pbs;  /* ID Payload; also used for hash calculation */
 
     certpolicy_t cert_policy = st->st_connection->spd.this.sendcert;
@@ -3498,6 +3479,8 @@ main_inR2_outI3(struct msg_digest *md)
                 || st->st_oakley.auth == XAUTHInitRSA
                 || st->st_oakley.auth == XAUTHRespRSA;
 
+    int auth_payload = RSA_auth ? ISAKMP_NEXT_SIG : ISAKMP_NEXT_HASH;
+
     /* KE in */
     RETURN_STF_FAILURE(accept_KE(&st->st_gr, "Gr", st->st_oakley.group, keyex_pbs));
 
@@ -3960,8 +3943,7 @@ main_inI3_outR3_tail(struct msg_digest *md
      */
     echo_hdr(md, TRUE, ISAKMP_NEXT_ID);
 
-    auth_payload = st->st_oakley.auth == OAKLEY_PRESHARED_KEY
-       ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_SIG;
+    auth_payload = RSA_auth ? ISAKMP_NEXT_SIG : ISAKMP_NEXT_HASH;
 
     /* IDir out */
     {
index 37cb6fb..7aea81f 100644 (file)
@@ -54,6 +54,7 @@
 #include "whack.h"     /* for RC_LOG_SERIOUS */
 #include "timer.h"
 #include "fetch.h"
+#include "xauth.h"
 
 const char *shared_secrets_file = SHARED_SECRETS_FILE;
 
@@ -97,11 +98,11 @@ allocate_RSA_public_key(const cert_t cert)
     default:
        plog("RSA public key allocation error");
     }
-    init_RSA_public_key(&pk->u.rsa, e, n);
 
-#ifdef DEBUG
-    DBG(DBG_PRIVATE, RSA_show_public_key(&pk->u.rsa));
-#endif
+    init_RSA_public_key(&pk->u.rsa, e, n);
+    DBG(DBG_RAW,
+       RSA_show_public_key(&pk->u.rsa)
+    )
 
     pk->alg = PUBKEY_ALG_RSA;
     pk->id  = empty_id;
@@ -182,7 +183,7 @@ get_secret(const struct connection *c, enum PrivateKeyKind kind, bool asym)
        his_id = &rw_id;
     }
     else if (kind == PPK_PSK
-    && (c->policy & POLICY_PSK)
+    && (c->policy & (POLICY_PSK | POLICY_XAUTH_PSK))
     && ((c->kind == CK_TEMPLATE && c->spd.that.id.kind == ID_NONE) ||
         (c->kind == CK_INSTANCE && id_is_ipaddr(&c->spd.that.id))))
     {
@@ -414,7 +415,7 @@ process_psk_secret(chunk_t *psk)
     }
     else
     {
-       char buf[RSA_MAX_ENCODING_BYTES];       /* limit on size of binary representation of key */
+       char buf[BUF_LEN];      /* limit on size of binary representation of key */
        size_t sz;
 
        ugh = ttodatav(tok, flp->cur - tok, 0, buf, sizeof(buf), &sz
@@ -589,7 +590,6 @@ static err_t
 process_xauth(secret_t *s)
 {
     chunk_t user_name;
-    chunk_t user_password;
 
     s->kind = PPK_XAUTH;
 
@@ -605,31 +605,21 @@ process_xauth(secret_t *s)
        user_name.ptr = tok;
        user_name.len = flp->cur - tok;
     }
+    plog("  loaded xauth credentials of user '%.*s'"
+               , user_name.len
+               , user_name.ptr);
+    clonetochunk(s->u.xauth_secret.user_name
+       , user_name.ptr, user_name.len, "xauth user name");
+
     if (!shift())
        return "missing xauth user password";
-    if (*tok == '"' || *tok == '\'')  /* quoted user password */
-    {
-       user_password.ptr = tok + 1;
-       user_password.len = flp->cur - tok - 2;
-    }
-    else
-    {
-       user_password.ptr = tok;
-       user_password.len = flp->cur - tok;
-    }
-    if (shift())
-       return "unexpected token after xauth user passpword";
-    clonetochunk(s->u.xauth_secret.user_name
-       , user_name.ptr, user_name.len, "user_name");
-    clonetochunk(s->u.xauth_secret.user_password
-       , user_password.ptr, user_password.len, "user_password");
-    return NULL;
+    return process_psk_secret(&s->u.xauth_secret.user_password);
 }
 
 /* get XAUTH secret from chained secrets lists
  * only one entry is currently supported
  */
-bool
+static bool
 xauth_get_secret(xauth_t *xauth_secret)
 {
     secret_t *s;
@@ -656,9 +646,10 @@ xauth_get_secret(xauth_t *xauth_secret)
 /*
  * find a matching secret
  */
-bool
+static bool
 xauth_verify_secret(const xauth_t *xauth_secret)
 {
+    bool found = FALSE;
     secret_t *s;
 
     for (s = secrets; s != NULL; s = s->next)
@@ -667,14 +658,45 @@ xauth_verify_secret(const xauth_t *xauth_secret)
        {
            if (!same_chunk(xauth_secret->user_name, s->u.xauth_secret.user_name))
                continue;
+           found = TRUE;
            if (same_chunk(xauth_secret->user_password, s->u.xauth_secret.user_password))
                return TRUE;
        }
     }
+    plog("xauth user '%.*s' %s"
+       , xauth_secret->user_name.len, xauth_secret->user_name.ptr
+       , found? "sent wrong password":"not found");
     return FALSE;
 }
 
 /*
+ * the global xauth_module struct is defined here
+ */
+xauth_module_t xauth_module;
+
+/*
+ * assign the default xauth functions to any null function pointers
+ */
+void
+xauth_defaults(void)
+{
+    if (xauth_module.get_secret == NULL)
+    {
+       DBG(DBG_CONTROL,
+           DBG_log("xauth_module: using default get_secret() function")
+       )
+       xauth_module.get_secret = xauth_get_secret;
+    }
+    if (xauth_module.verify_secret == NULL)
+    {
+       DBG(DBG_CONTROL,
+           DBG_log("xauth_module: using default verify_secret() function")
+       )
+       xauth_module.verify_secret = xauth_verify_secret;
+    }
+};
+
+/*
  * process pin read from ipsec.secrets or prompted for it using whack
  */
 static err_t
@@ -1202,14 +1224,11 @@ unpack_RSA_public_key(RSA_public_key_t *rsa, const chunk_t *pubkey)
        return RSA_MAX_OCTETS_UGH;
 
     init_RSA_public_key(rsa, exp, mod);
-
-#ifdef DEBUG
-    DBG(DBG_PRIVATE, RSA_show_public_key(rsa));
-#endif
-
-
     rsa->k = mpz_sizeinbase(&rsa->n, 2);       /* size in bits, for a start */
     rsa->k = (rsa->k + BITS_PER_BYTE - 1) / BITS_PER_BYTE;     /* now octets */
+    DBG(DBG_RAW,
+       RSA_show_public_key(rsa)
+    )
 
     if (rsa->k != mod.len)
     {
index 3e583e4..d1442ce 100644 (file)
@@ -41,6 +41,11 @@ enum PrivateKeyKind {
     PPK_PIN
 };
 
+extern void xauth_defaults(void);
+
+/* forward declaration */
+struct connection;
+
 extern const chunk_t *get_preshared_secret(const struct connection *c);
 extern err_t unpack_RSA_public_key(RSA_public_key_t *rsa, const chunk_t *pubkey);
 extern const RSA_private_key_t *get_RSA_private_key(const struct connection *c);
@@ -86,7 +91,6 @@ extern void delete_public_keys(const struct id *id, enum pubkey_alg alg
 extern pubkey_t *reference_key(pubkey_t *pk);
 extern void unreference_key(pubkey_t **pkp);
 
-
 extern err_t add_public_key(const struct id *id
     , enum dns_auth_level dns_auth_level
     , enum pubkey_alg alg
@@ -101,16 +105,6 @@ extern void add_pgp_public_key(pgpcert_t *cert, time_t until
 extern void remove_x509_public_key(const x509cert_t *cert);
 extern void list_public_keys(bool utc);
 
-/* XAUTH credentials */
-
-typedef struct {
-    chunk_t user_name;
-    chunk_t user_password;
-} xauth_t;
-
-extern bool xauth_get_secrect(const xauth_t *xauth_secret);
-extern bool xauth_verify_secret(const xauth_t *xauth_secret);
-
 struct gw_info;        /* forward declaration of tag (defined in dnskey.h) */
 extern void transfer_to_public_keys(struct gw_info *gateways_from_dns
 #ifdef USE_KEYRR
index af2ee30..2fcc27d 100644 (file)
@@ -39,7 +39,9 @@
 #include "crypto.h"
 #include "modecfg.h"
 #include "whack.h"
-#include "keys.h"
+#include "xauth.h"
+
+#define MAX_XAUTH_TRIES                3
 
 #define SUPPORTED_ATTR_SET   ( LELEM(INTERNAL_IP4_ADDRESS) \
                              | LELEM(INTERNAL_IP4_NETMASK) \
@@ -410,6 +412,7 @@ modecfg_send_msg(struct state *st, int isama_type, internal_addr_t *ia)
                        , 0 /* XXX isama_id */
                     );
 
+    freeanychunk(st->st_tpacket);
     clonetochunk(st->st_tpacket, msg.start, pbs_offset(&msg), "ModeCfg msg");
 
     /* Transmit */
@@ -424,67 +427,6 @@ modecfg_send_msg(struct state *st, int isama_type, internal_addr_t *ia)
 }
 
 /*
- * Send ModeCfg request message from client to server in pull mode
- */
-stf_status
-modecfg_send_request(struct state *st)
-{
-    stf_status stat;
-    internal_addr_t ia;
-
-    init_internal_addr(&ia);
-    ia.attr_set = LELEM(INTERNAL_IP4_ADDRESS)
-               | LELEM(INTERNAL_IP4_NETMASK);
-
-    plog("sending ModeCfg request");
-    st->st_state = STATE_MODE_CFG_I1;
-    stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia);
-    if (stat == STF_OK)
-       st->st_modecfg.started = TRUE;
-    return stat;
-}
-
-/*
- * Send ModeCfg set message from server to client in push mode
- */
-stf_status
-modecfg_send_set(struct state *st)
-{
-    stf_status stat;
-    internal_addr_t ia;
-
-    get_internal_addr(st->st_connection, &ia);
-
-    plog("sending ModeCfg set");
-    st->st_state = STATE_MODE_CFG_R1;
-    stat = modecfg_send_msg(st, ISAKMP_CFG_SET, &ia);
-    if (stat == STF_OK)
-       st->st_modecfg.started = TRUE;
-    return stat;
-}
-
-/*
- * Send XAUTH credentials request (username + password)
- */
-stf_status
-xauth_send_request(struct state *st)
-{
-    stf_status stat;
-    internal_addr_t ia;
-
-    init_internal_addr(&ia);
-    ia.attr_set = LELEM(XAUTH_USER_NAME     - XAUTH_BASE + MODECFG_ROOF)
-               | LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE + MODECFG_ROOF);
-
-    plog("sending XAUTH request");
-    st->st_state = STATE_XAUTH_R1;
-    stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia);
-    if (stat == STF_OK)
-       st->st_xauth.started = TRUE;
-    return stat;
-}
-
-/*
  * Parse a ModeCfg attribute payload
  */
 static stf_status
@@ -595,6 +537,27 @@ modecfg_parse_msg(struct msg_digest *md, int isama_type, u_int16_t *isama_id
     return STF_IGNORE;
 }
 
+/*
+ * Send ModeCfg request message from client to server in pull mode
+ */
+stf_status
+modecfg_send_request(struct state *st)
+{
+    stf_status stat;
+    internal_addr_t ia;
+
+    init_internal_addr(&ia);
+    ia.attr_set = LELEM(INTERNAL_IP4_ADDRESS)
+               | LELEM(INTERNAL_IP4_NETMASK);
+
+    plog("sending ModeCfg request");
+    st->st_state = STATE_MODE_CFG_I1;
+    stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia);
+    if (stat == STF_OK)
+       st->st_modecfg.started = TRUE;
+    return stat;
+}
+
 /* STATE_MODE_CFG_R0:
  * HDR*, HASH, ATTR(REQ=IP) --> HDR*, HASH, ATTR(REPLY=IP)
  *
@@ -606,91 +569,84 @@ modecfg_inR0(struct msg_digest *md)
     struct state *const st = md->st;
     u_int16_t isama_id;
     internal_addr_t ia;
-    stf_status stat;
+    stf_status stat, stat_build;
 
     stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, &ia);
     if (stat != STF_OK)
        return stat;
-
     get_internal_addr(st->st_connection, &ia);
 
     plog("sending ModeCfg reply");
 
-    stat = modecfg_build_msg(st, &md->rbody
-                              , ISAKMP_CFG_REPLY
-                              , &ia
-                              , isama_id);
-    if (stat != STF_OK)
-    {
-       /* notification payload - not exactly the right choice, but okay */
-       md->note = ATTRIBUTES_NOT_SUPPORTED;
-       return stat;
-    }
+    stat_build = modecfg_build_msg(st, &md->rbody
+                                    , ISAKMP_CFG_REPLY
+                                    , &ia
+                                    , isama_id);
+    if (stat_build != STF_OK)
+       return stat_build;
 
     st->st_msgid = 0;
     return STF_OK;
 }
 
-/* STATE_MODE_CFG_R1:
- * HDR*, HASH, ATTR(ACK,OK)
+/* STATE_MODE_CFG_I1:
+ * HDR*, HASH, ATTR(REPLY=IP)
  *
- * used in ModeCfg push mode, on the server (responder)
+ * used in ModeCfg pull mode, on the client (initiator) 
  */
 stf_status
-modecfg_inR1(struct msg_digest *md)
+modecfg_inI1(struct msg_digest *md)
 {
     struct state *const st = md->st;
     u_int16_t isama_id;
     internal_addr_t ia;
     stf_status stat;
 
-    plog("parsing ModeCfg ack");
+    plog("parsing ModeCfg reply");
 
-    stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, &ia);
+    stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia);
     if (stat != STF_OK)
        return stat;
 
+    st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia);
     st->st_msgid = 0;
     return STF_OK;
 }
 
-/* STATE_MODE_CFG_I1:
- * HDR*, HASH, ATTR(REPLY=IP)
- *
- * used in ModeCfg pull mode, on the client (initiator) 
+
+/*
+ * Send ModeCfg set message from server to client in push mode
  */
 stf_status
-modecfg_inI1(struct msg_digest *md)
+modecfg_send_set(struct state *st)
 {
-    struct state *const st = md->st;
-    u_int16_t isama_id;
-    internal_addr_t ia;
     stf_status stat;
+    internal_addr_t ia;
 
-    plog("parsing ModeCfg reply");
-
-    stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia);
-    if (stat != STF_OK)
-       return stat;
+    get_internal_addr(st->st_connection, &ia);
 
-    st->st_modecfg.vars_set = set_internal_addr(st->st_connection, &ia);
-    st->st_msgid = 0;
-    return STF_OK;
+    plog("sending ModeCfg set");
+    st->st_state = STATE_MODE_CFG_R3;
+    stat = modecfg_send_msg(st, ISAKMP_CFG_SET, &ia);
+    if (stat == STF_OK)
+       st->st_modecfg.started = TRUE;
+    return stat;
 }
 
-/* STATE_MODE_CFG_I2:
+/* STATE_MODE_CFG_I0:
  *  HDR*, HASH, ATTR(SET=IP) --> HDR*, HASH, ATTR(ACK,OK)
  *
  * used in ModeCfg push mode, on the client (initiator).
  */
 stf_status
-modecfg_inI2(struct msg_digest *md)
+modecfg_inI0(struct msg_digest *md)
 {
     struct state *const st = md->st;
     u_int16_t isama_id;
     internal_addr_t ia;
     lset_t attr_set;
-    stf_status stat;
+    stf_status stat, stat_build;
 
     plog("parsing ModeCfg set");
 
@@ -707,95 +663,59 @@ modecfg_inI2(struct msg_digest *md)
 
     plog("sending ModeCfg ack");
 
-    stat = modecfg_build_msg(st, &md->rbody
-                              , ISAKMP_CFG_ACK
-                              , &ia
-                              , isama_id);
-    if (stat != STF_OK)
-    {
-       /* notification payload - not exactly the right choice, but okay */
-       md->note = ATTRIBUTES_NOT_SUPPORTED;
-       return stat;
-    }
+    stat_build = modecfg_build_msg(st, &md->rbody
+                                    , ISAKMP_CFG_ACK
+                                    , &ia
+                                    , isama_id);
+    if (stat_build != STF_OK)
+       return stat_build;
 
     st->st_msgid = 0;
     return STF_OK;
 }
 
-/* STATE_XAUTH_R1:
- *  HDR*, HASH, ATTR(REPLY=USERNAME/PASSWORD) --> HDR*, HASH, ATTR(STATUS)
+/* STATE_MODE_CFG_R3:
+ * HDR*, HASH, ATTR(ACK,OK)
  *
- *  used on the XAUTH server (responder)
+ * used in ModeCfg push mode, on the server (responder)
  */
 stf_status
-xauth_inR1(struct msg_digest *md)
+modecfg_inR3(struct msg_digest *md)
 {
     struct state *const st = md->st;
     u_int16_t isama_id;
     internal_addr_t ia;
     stf_status stat;
-    bool status;
 
-    plog("parsing XAUTH reply");
+    plog("parsing ModeCfg ack");
 
-    stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia);
+    stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, &ia);
     if (stat != STF_OK)
        return stat;
 
-    /* check XAUTH reply */
-    if ((ia.attr_set & LELEM(XAUTH_STATUS - XAUTH_BASE + MODECFG_ROOF)) != LEMPTY)
-    {
-       plog("received FAIL status in XAUTH reply");
-       return STF_INTERNAL_ERROR;
-    }
-    if ((ia.attr_set & LELEM(XAUTH_USER_NAME - XAUTH_BASE + MODECFG_ROOF)) == LEMPTY)
-    {
-       plog("user name attribute is missing in XAUTH reply");
-       return STF_SUSPEND;
-    }
-    if ((ia.attr_set & LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE + MODECFG_ROOF)) == LEMPTY)
-    {
-       plog("user password attribute is missing in XAUTH reply");
-       return STF_SUSPEND;
-    }
-
-    status = xauth_verify_secret(&ia.xauth_secret);
-
-    /* prepare XAUTH set which sends the authentication status */
-    init_internal_addr(&ia);
-    ia.attr_set = LELEM(XAUTH_STATUS - XAUTH_BASE + MODECFG_ROOF);
-    ia.xauth_status = status;
-
-    plog("sending XAUTH status: %s", status? "OK":"FAIL");
-
-    stat = modecfg_build_msg(st, &md->rbody
-                              , ISAKMP_CFG_SET
-                              , &ia
-                              , isama_id);
+    st->st_msgid = 0;
     return STF_OK;
 }
 
-/* STATE_XAUTH_R2:
- * HDR*, ATTR(STATUS), HASH --> Done
- *
- * used on the XAUTH server (responder)
+/*
+ * Send XAUTH credentials request (username + password)
  */
 stf_status
-xauth_inR2(struct msg_digest *md)
+xauth_send_request(struct state *st)
 {
-    struct state *const st = md->st;
-    u_int16_t isama_id;
-    internal_addr_t ia;
     stf_status stat;
+    internal_addr_t ia;
 
-    plog("parsing XAUTH ack");
-
-    stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, &ia);
-    if (stat != STF_OK)
-       return stat;
+    init_internal_addr(&ia);
+    ia.attr_set = LELEM(XAUTH_USER_NAME     - XAUTH_BASE + MODECFG_ROOF)
+               | LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE + MODECFG_ROOF);
 
-    st->st_msgid = 0;
-    return STF_OK;
+    plog("sending XAUTH request");
+    st->st_state = STATE_XAUTH_R1;
+    stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, &ia);
+    if (stat == STF_OK)
+       st->st_xauth.started = TRUE;
+    return stat;
 }
 
 /* STATE_XAUTH_I0:
@@ -809,7 +729,7 @@ xauth_inI0(struct msg_digest *md)
     struct state *const st = md->st;
     u_int16_t isama_id;
     internal_addr_t ia;
-    stf_status stat;
+    stf_status stat, stat_build;
 
     plog("parsing XAUTH request");
 
@@ -817,19 +737,19 @@ xauth_inI0(struct msg_digest *md)
     if (stat != STF_OK)
        return stat;
  
-    /* check XAUTH request */
+    /* check XAUTH attributes */
     if ((ia.attr_set & LELEM(XAUTH_TYPE - XAUTH_BASE + MODECFG_ROOF)) != LEMPTY
     && ia.xauth_type != XAUTH_TYPE_GENERIC)
     {
        plog("xauth type %s is not supported", enum_name(&xauth_type_names, ia.xauth_type));
        stat = STF_FAIL;
     }
-    if ((ia.attr_set & LELEM(XAUTH_USER_NAME - XAUTH_BASE + MODECFG_ROOF)) == LEMPTY)
+    else if ((ia.attr_set & LELEM(XAUTH_USER_NAME - XAUTH_BASE + MODECFG_ROOF)) == LEMPTY)
     {
        plog("user name attribute is missing in XAUTH request");
        stat = STF_FAIL;
     }
-    if ((ia.attr_set & LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE + MODECFG_ROOF)) == LEMPTY)
+    else if ((ia.attr_set & LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE + MODECFG_ROOF)) == LEMPTY)
     {
        plog("user password attribute is missing in XAUTH request");
        stat = STF_FAIL;
@@ -840,8 +760,8 @@ xauth_inI0(struct msg_digest *md)
 
     if (stat == STF_OK)
     {
-       /* get user credentials */
-       if (!xauth_get_secret(&ia.xauth_secret))
+       /* get user credentials using a plugin function */
+       if (!xauth_module.get_secret(&ia.xauth_secret))
        {
            plog("xauth user credentials not found");
            stat = STF_FAIL;
@@ -849,6 +769,16 @@ xauth_inI0(struct msg_digest *md)
     }
     if (stat == STF_OK)
     {
+       DBG(DBG_CONTROL,
+           DBG_log("my xauth user name is '%.*s'"
+                  , ia.xauth_secret.user_name.len
+                  , ia.xauth_secret.user_name.ptr)
+       )
+       DBG(DBG_PRIVATE,
+           DBG_log("my xauth user password is '%.*s'"
+                  , ia.xauth_secret.user_password.len
+                  , ia.xauth_secret.user_password.ptr)
+       )
        ia.attr_set = LELEM(XAUTH_USER_NAME - XAUTH_BASE + MODECFG_ROOF)
                    | LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE + MODECFG_ROOF);
     }
@@ -860,17 +790,100 @@ xauth_inI0(struct msg_digest *md)
 
     plog("sending XAUTH reply");
 
-    stat = modecfg_build_msg(st, &md->rbody
-                              , ISAKMP_CFG_REPLY
-                              , &ia
-                              , isama_id);
-    if (stat != STF_OK)
+    stat_build = modecfg_build_msg(st, &md->rbody
+                                    , ISAKMP_CFG_REPLY
+                                    , &ia
+                                    , isama_id);
+    if (stat_build != STF_OK)
+       return stat_build;
+
+    if (stat == STF_OK)
     {
-       /* notification payload - not exactly the right choice, but okay */
-       md->note = ATTRIBUTES_NOT_SUPPORTED;
+       st->st_xauth.started = TRUE;
+       return STF_OK;
+    }
+    else
+    {
+       /* send XAUTH reply msg and then delete ISAKMP SA */
+       freeanychunk(st->st_tpacket);
+       clonetochunk(st->st_tpacket, md->reply.start
+           , pbs_offset(&md->reply), "XAUTH reply msg");
+       send_packet(st, "XAUTH reply msg");
+       delete_state(st);
+       return STF_IGNORE;
+    }
+}
+
+/* STATE_XAUTH_R1:
+ *  HDR*, HASH, ATTR(REPLY=USERNAME/PASSWORD) --> HDR*, HASH, ATTR(STATUS)
+ *
+ *  used on the XAUTH server (responder)
+ */
+stf_status
+xauth_inR1(struct msg_digest *md)
+{
+    struct state *const st = md->st;
+    u_int16_t isama_id;
+    internal_addr_t ia;
+    stf_status stat, stat_build;
+
+    plog("parsing XAUTH reply");
+
+    stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, &ia);
+    if (stat != STF_OK)
        return stat;
+    /* did the client return an XAUTH FAIL status? */
+    if ((ia.attr_set & LELEM(XAUTH_STATUS - XAUTH_BASE + MODECFG_ROOF)) != LEMPTY)
+    {
+       plog("received FAIL status in XAUTH reply");
+
+       /* client is not able to do XAUTH, delete ISAKMP SA */
+       delete_state(st);
+       return STF_IGNORE;
+    }
+
+    /* check XAUTH reply */
+    if ((ia.attr_set & LELEM(XAUTH_USER_NAME - XAUTH_BASE + MODECFG_ROOF)) == LEMPTY)
+    {
+       plog("user name attribute is missing in XAUTH reply");
+       st->st_xauth.status = FALSE;
     }
-    st->st_xauth.started = TRUE;
+    else if ((ia.attr_set & LELEM(XAUTH_USER_PASSWORD - XAUTH_BASE + MODECFG_ROOF)) == LEMPTY)
+    {
+       plog("user password attribute is missing in XAUTH reply");
+       st->st_xauth.status = FALSE;
+    }
+    else 
+    {
+       DBG(DBG_CONTROL,
+           DBG_log("peer xauth user name is '%.*s'"
+                  , ia.xauth_secret.user_name.len
+                  , ia.xauth_secret.user_name.ptr)
+       )
+       DBG(DBG_PRIVATE,
+           DBG_log("peer xauth user password is '%.*s'"
+                  , ia.xauth_secret.user_password.len
+                  , ia.xauth_secret.user_password.ptr)
+       )
+       /* verify the user credentials using a plugn function */
+       st->st_xauth.status = xauth_module.verify_secret(&ia.xauth_secret);
+       plog("extended authentication %s", st->st_xauth.status? "was successful":"failed");
+    }
+
+    /* prepare XAUTH set which sends the authentication status */
+    init_internal_addr(&ia);
+    ia.attr_set = LELEM(XAUTH_STATUS - XAUTH_BASE + MODECFG_ROOF);
+    ia.xauth_status = st->st_xauth.status;
+
+    plog("sending XAUTH status:");
+
+    stat_build = modecfg_build_msg(st, &md->rbody
+                                    , ISAKMP_CFG_SET
+                                    , &ia
+                                    , isama_id);
+     if (stat_build != STF_OK)
+       return stat_build;
     return STF_OK;
 }
 
@@ -882,26 +895,76 @@ xauth_inI0(struct msg_digest *md)
 stf_status
 xauth_inI1(struct msg_digest *md)
 {
-     struct state *const st = md->st;
+    struct state *const st = md->st;
     u_int16_t isama_id;
     internal_addr_t ia;
-    stf_status stat;
+    stf_status stat, stat_build;
 
     plog("parsing XAUTH status");
-
     stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, &ia);
     if (stat != STF_OK)
+    {
+       /* notification payload - not exactly the right choice, but okay */
+       md->note = ATTRIBUTES_NOT_SUPPORTED;
        return stat;
+    }
 
-    /* prepare XAUTH set which sends the authentication status */
-    init_internal_addr(&ia);
+    st->st_xauth.status = ia.xauth_status;
+    plog("extended authentication %s", st->st_xauth.status? "was successful":"failed");
 
     plog("sending XAUTH ack");
+    init_internal_addr(&ia);
+    stat_build = modecfg_build_msg(st, &md->rbody
+                                    , ISAKMP_CFG_ACK
+                                    , &ia
+                                    , isama_id);
+    if (stat_build != STF_OK)
+       return stat_build;
+    if (st->st_xauth.status)
+    {
+       st->st_msgid = 0;
+       return STF_OK;
+    }
+    else
+    {
+       /* send XAUTH ack msg and then delete ISAKMP SA */
+       freeanychunk(st->st_tpacket);
+       clonetochunk(st->st_tpacket, md->reply.start
+           , pbs_offset(&md->reply), "XAUTH ack msg");
+       send_packet(st, "XAUTH ack msg");
+       delete_state(st);
+       return STF_IGNORE;
+    }
+}
+
+/* STATE_XAUTH_R2:
+ * HDR*, ATTR(STATUS), HASH --> Done
+ *
+ * used on the XAUTH server (responder)
+ */
+stf_status
+xauth_inR2(struct msg_digest *md)
+{
+    struct state *const st = md->st;
+    u_int16_t isama_id;
+    internal_addr_t ia;
+    stf_status stat;
+
+    plog("parsing XAUTH ack");
+
+    stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, &ia);
+    if (stat != STF_OK)
+       return stat;
 
-    stat = modecfg_build_msg(st, &md->rbody
-                              , ISAKMP_CFG_ACK
-                              , &ia
-                              , isama_id);
     st->st_msgid = 0;
-    return stat;
+    if (st->st_xauth.status)
+    {
+       return STF_OK;
+    }
+    else
+    {
+       delete_state(st);
+       return STF_IGNORE;
+    }
 }
index fe00067..68b7ef4 100644 (file)
 struct state;
 struct msg_digest;
 
-/* ModeConfig starting functions */
+/* ModeConfig pull mode start function */
 extern stf_status modecfg_send_request(struct state *st);
-extern stf_status modecfg_send_set(struct state *st);
 
-/* ModeConfig state transition functions */
+/* ModeConfig pull mode state transition functions */
 extern stf_status modecfg_inR0(struct msg_digest *md);
-extern stf_status modecfg_inR1(struct msg_digest *md);
 extern stf_status modecfg_inI1(struct msg_digest *md);
-extern stf_status modecfg_inI2(struct msg_digest *md);
+
+/* ModeConfig push mode start function */
+extern stf_status modecfg_send_set(struct state *st);
+
+/* ModeConfig push mode state transition functions */
+extern stf_status modecfg_inI0(struct msg_digest *md);
+extern stf_status modecfg_inR3(struct msg_digest *md);
 
 /* XAUTH start function */
 extern stf_status xauth_send_request(struct state *st);
 
 /* XAUTH state transition funcgtions */
-extern stf_status xauth_inR1(struct msg_digest *md);
-extern stf_status xauth_inR2(struct msg_digest *md);
 extern stf_status xauth_inI0(struct msg_digest *md);
+extern stf_status xauth_inR1(struct msg_digest *md);
 extern stf_status xauth_inI1(struct msg_digest *md);
+extern stf_status xauth_inR2(struct msg_digest *md);
 
 #endif /* _MODECFG_H */
index 2c34fc9..d3a9805 100644 (file)
@@ -216,6 +216,7 @@ struct state
     struct {
        int attempt;
        bool started;
+       bool status;
     } st_xauth;
 
     u_int32_t         nat_traversal;
index 4983a45..54333c4 100644 (file)
@@ -394,6 +394,9 @@ handle_known_vendorid (struct msg_digest *md
        md->dpd = TRUE;
        vid_useful = TRUE;
        break;
+    case VID_MISC_XAUTH:
+       vid_useful = TRUE;
+       break;
     default:
        break;
     }
diff --git a/src/pluto/xauth.c b/src/pluto/xauth.c
new file mode 100644 (file)
index 0000000..e44ac4e
--- /dev/null
@@ -0,0 +1,36 @@
+/* Initialization and finalization of the dynamic XAUTH module
+ * Copyright (C) 2006 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: xauth.c,v 1.1 2005/01/06 22:10:15 as Exp $
+ */
+
+#include <freeswan.h>
+
+#include "constants.h"
+#include "defs.h"
+#include "xauth.h"
+#include "keys.h"
+
+void 
+xauth_init(void)
+{
+    /* TODO: locate and load dynamic XAUTH module */
+    xauth_defaults();
+}
+
+void
+xauth_finalize(void)
+{
+    /* TODO: unload dynamic XAUTH module */
+}
diff --git a/src/pluto/xauth.h b/src/pluto/xauth.h
new file mode 100644 (file)
index 0000000..f60d1d0
--- /dev/null
@@ -0,0 +1,40 @@
+/* Interface definition of the XAUTH server and|or client module
+ * Copyright (C) 2006 Andreas Steffen
+ * Hochschule fuer Technik Rapperswil, Switzerland
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: xauth.h,v 1.1 2005/01/06 22:10:15 as Exp $
+ */
+
+#ifndef _XAUTH_H
+#define _XAUTH_H
+
+/* XAUTH credentials */
+
+struct chunk_t;
+
+typedef struct {
+    chunk_t user_name;
+    chunk_t user_password;
+} xauth_t;
+
+typedef struct {
+    bool (*get_secret) (const xauth_t *xauth_secret);
+    bool (*verify_secret) (const xauth_t *xauth_secret);
+} xauth_module_t;
+
+extern xauth_module_t xauth_module;
+
+extern void xauth_init(void);
+extern void xauth_finalize(void);
+
+#endif /* _XAUTH_H */