payload: Use common prefixes for all payload type identifiers
[strongswan.git] / src / libcharon / plugins / eap_gtc / eap_gtc.c
index 7ae16d7..5fcd9eb 100644 (file)
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2007 Martin Willi
+ * Copyright (C) 2007-2012 Martin Willi
+ * Copyright (C) 2012 revosec AG
  * Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
 
 #include <daemon.h>
 #include <library.h>
-#include <crypto/hashers/hasher.h>
-
-#include <security/pam_appl.h>
 
 #define GTC_REQUEST_MSG "password"
-#define GTC_PAM_SERVICE "login"
 
 typedef struct private_eap_gtc_t private_eap_gtc_t;
 
@@ -77,63 +74,6 @@ METHOD(eap_method_t, initiate_peer, status_t,
        return FAILED;
 }
 
-/**
- * PAM conv callback function
- */
-static int auth_conv(int num_msg, const struct pam_message **msg,
-                                        struct pam_response **resp, char *password)
-{
-       struct pam_response *response;
-
-       if (num_msg != 1)
-       {
-               return PAM_CONV_ERR;
-       }
-       response = malloc(sizeof(struct pam_response));
-       response->resp = strdup(password);
-       response->resp_retcode = 0;
-       *resp = response;
-       return PAM_SUCCESS;
-}
-
-/**
- * Authenticate a username/password using PAM
- */
-static bool authenticate(char *service, char *user, char *password)
-{
-       pam_handle_t *pamh = NULL;
-       static struct pam_conv conv;
-       int ret;
-
-       conv.conv = (void*)auth_conv;
-       conv.appdata_ptr = password;
-
-       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)
-       {
-               ret = pam_acct_mgmt(pamh, 0);
-               if (ret != PAM_SUCCESS)
-               {
-                       DBG1(DBG_IKE, "EAP-GTC pam_acct_mgmt failed: %s",
-                                pam_strerror(pamh, ret));
-               }
-       }
-       else
-       {
-               DBG1(DBG_IKE, "EAP-GTC pam_authenticate failed: %s",
-                        pam_strerror(pamh, ret));
-       }
-       pam_end(pamh, ret);
-       return ret == PAM_SUCCESS;
-}
-
 METHOD(eap_method_t, initiate_server, status_t,
        private_eap_gtc_t *this, eap_payload_t **out)
 {
@@ -174,10 +114,11 @@ METHOD(eap_method_t, process_peer, status_t,
 
        /* TODO: According to the draft we should "SASLprep" password, RFC4013. */
 
+       this->identifier = in->get_identifier(in);
        res = alloca(sizeof(eap_gtc_header_t) + len);
        res->length = htons(sizeof(eap_gtc_header_t) + len);
        res->code = EAP_RESPONSE;
-       res->identifier = in->get_identifier(in);
+       res->identifier = this->identifier;
        res->type = EAP_GTC;
        memcpy(res->data, key.ptr, len);
 
@@ -191,39 +132,57 @@ METHOD(eap_method_t, process_peer, status_t,
 METHOD(eap_method_t, process_server, status_t,
        private_eap_gtc_t *this, eap_payload_t *in, eap_payload_t **out)
 {
-       chunk_t data, encoding;
-       char *user, *password, *service, *pos;
-
-       data = chunk_skip(in->get_data(in), 5);
-       if (this->identifier != in->get_identifier(in) || !data.len)
+       status_t status = FAILED;
+       chunk_t user, pass;
+       xauth_method_t *xauth;
+       cp_payload_t *ci, *co;
+       char *backend;
+
+       user = this->peer->get_encoding(this->peer);
+       pass = chunk_skip(in->get_data(in), 5);
+       if (this->identifier != in->get_identifier(in) || !pass.len)
        {
                DBG1(DBG_IKE, "received invalid EAP-GTC message");
                return FAILED;
        }
 
-       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)
+       /* get XAuth backend to use for credential verification. Default to PAM
+        * to support legacy EAP-GTC configurations */
+       backend = lib->settings->get_str(lib->settings,
+                                                               "%s.plugins.eap-gtc.backend", "pam", lib->ns);
+       xauth = charon->xauth->create_instance(charon->xauth, backend, XAUTH_SERVER,
+                                                                                  this->server, this->peer);
+       if (!xauth)
        {
-               encoding.len = (u_char*)pos - encoding.ptr;
+               DBG1(DBG_IKE, "creating EAP-GTC XAuth backend '%s' failed", backend);
+               return FAILED;
        }
-       user = alloca(encoding.len + 1);
-       memcpy(user, encoding.ptr, encoding.len);
-       user[encoding.len] = '\0';
-
-       password = alloca(data.len + 1);
-       memcpy(password, data.ptr, data.len);
-       password[data.len] = '\0';
-
-       service = lib->settings->get_str(lib->settings,
-                                               "charon.plugins.eap-gtc.pam_service", GTC_PAM_SERVICE);
-
-       if (!authenticate(service, user, password))
+       if (xauth->initiate(xauth, &co) == NEED_MORE)
        {
-               return FAILED;
+               /* assume that "out" contains username/password attributes */
+               co->destroy(co);
+               ci = cp_payload_create_type(PLV1_CONFIGURATION, CFG_REPLY);
+               ci->add_attribute(ci, configuration_attribute_create_chunk(
+                                       PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_NAME, user));
+               ci->add_attribute(ci, configuration_attribute_create_chunk(
+                                       PLV1_CONFIGURATION_ATTRIBUTE, XAUTH_USER_PASSWORD, pass));
+               switch (xauth->process(xauth, ci, &co))
+               {
+                       case SUCCESS:
+                               status = SUCCESS;
+                               break;
+                       case NEED_MORE:
+                               /* TODO: multiple exchanges currently not supported */
+                               co->destroy(co);
+                               break;
+                       case FAILED:
+                       default:
+                               break;
+               }
+               ci->destroy(ci);
        }
-       return SUCCESS;
+       xauth->destroy(xauth);
+       return status;
 }
 
 METHOD(eap_method_t, get_type, eap_type_t,
@@ -321,4 +280,3 @@ eap_gtc_t *eap_gtc_create_peer(identification_t *server, identification_t *peer)
 
        return &this->public;
 }
-