use username part of RFC822 IDs for PAM authentication
[strongswan.git] / src / charon / plugins / eap_gtc / eap_gtc.c
index f178786..5f6f655 100644 (file)
@@ -23,7 +23,7 @@
 
 #include <security/pam_appl.h>
 
-#define GTC_REQUEST_MSG "login"
+#define GTC_REQUEST_MSG "password"
 #define GTC_PAM_SERVICE "login"
 
 typedef struct private_eap_gtc_t private_eap_gtc_t;
@@ -105,18 +105,26 @@ static int auth_conv(int num_msg, const struct pam_message **msg,
  */
 static bool authenticate(char *service, char *user, char *password)
 {
-    pam_handle_t *pamh;
+    pam_handle_t *pamh = NULL;
        static struct pam_conv conv;
     int ret;
        
        conv.conv = (void*)auth_conv;
        conv.appdata_ptr = password;
        
-       if (pam_start(service, user, &conv, &pamh) != PAM_SUCCESS)
+       ret = pam_start(service, user, &conv, &pamh);
+       if (ret != PAM_SUCCESS)
        {
+               DBG1(DBG_IKE, "EAP-GTC pam_start failed: %s",
+                        pam_strerror(pamh, ret));
                return FALSE;
        }
        ret = pam_authenticate(pamh, 0);
+       if (ret != PAM_SUCCESS)
+       {
+               DBG1(DBG_IKE, "EAP-GTC pam_authenticate failed: %s",
+                        pam_strerror(pamh, ret));
+       }
        pam_end(pamh, ret);
        return ret == PAM_SUCCESS;
 }
@@ -154,15 +162,17 @@ static status_t process_peer(private_eap_gtc_t *this,
        size_t len;
 
        shared = charon->credentials->get_shared(charon->credentials, SHARED_EAP,
-                                                                                        this->server, this->peer);
+                                                                                        this->peer, this->server);
        if (shared == NULL)
        {
                DBG1(DBG_IKE, "no EAP key found for '%D' - '%D'",
-                        this->server, this->peer);
+                        this->peer, this->server);
                return FAILED;
        }
        key = shared->get_key(shared);
        len = key.len;
+       
+       /* TODO: According to the draft we should "SASLprep" password, RFC4013. */
 
        res = alloca(sizeof(eap_gtc_header_t) + len);
        res->length = htons(sizeof(eap_gtc_header_t) + len);
@@ -185,7 +195,7 @@ static status_t process_server(private_eap_gtc_t *this,
                                                           eap_payload_t *in, eap_payload_t **out)
 {
        chunk_t data, encoding;
-       char *user, *password, *service;
+       char *user, *password, *service, *pos;
        
        data = chunk_skip(in->get_data(in), 5);
        if (this->identifier != in->get_identifier(in) || !data.len)
@@ -195,6 +205,12 @@ static status_t process_server(private_eap_gtc_t *this,
        }
        
        encoding = this->peer->get_encoding(this->peer);
+       /* if a RFC822_ADDR id is provided, we use the username part only */
+       pos = memchr(encoding.ptr, '@', encoding.len);
+       if (pos)
+       {
+               encoding.len = (u_char*)pos - encoding.ptr;
+       }
        user = alloca(encoding.len + 1);
        memcpy(user, encoding.ptr, encoding.len);
        user[encoding.len] = '\0';
@@ -206,11 +222,8 @@ static status_t process_server(private_eap_gtc_t *this,
        service = lib->settings->get_str(lib->settings,
                                                "charon.plugins.eap_gtc.pam_service", GTC_PAM_SERVICE);
        
-       /* TODO: According to the draft we should "SASLprep" username and
-        * passwords... RFC4013 */
        if (!authenticate(service, user, password))
        {
-               DBG1(DBG_IKE, "EAP-GTC PAM authentication failed");
                return FAILED;
        }
        return SUCCESS;
@@ -246,6 +259,8 @@ static bool is_mutual(private_eap_gtc_t *this)
  */
 static void destroy(private_eap_gtc_t *this)
 {
+       this->peer->destroy(this->peer);
+       this->server->destroy(this->server);
        free(this);
 }
 
@@ -265,9 +280,9 @@ static private_eap_gtc_t *eap_gtc_create_generic(identification_t *server,
        this->public.eap_method_interface.destroy = (void(*)(eap_method_t*))destroy;
        
        /* private data */
-       this->peer = peer;
-       this->server = server;
-       this->identifier = random();
+       this->peer = peer->clone(peer);
+       this->server = server->clone(server);
+       this->identifier = 0;
        
        return this;
 }
@@ -282,6 +297,11 @@ eap_gtc_t *eap_gtc_create_server(identification_t *server, identification_t *pee
        this->public.eap_method_interface.initiate = (status_t(*)(eap_method_t*,eap_payload_t**))initiate_server;
        this->public.eap_method_interface.process = (status_t(*)(eap_method_t*,eap_payload_t*,eap_payload_t**))process_server;
 
+       /* generate a non-zero identifier */
+       do {
+               this->identifier = random();
+       } while (!this->identifier);
+
        return &this->public;
 }