Create Module-Failure-Message for *all* callback errors
[freeradius.git] / src / modules / rlm_eap / libeap / cb.c
index 7b2f1b9..72d41d3 100644 (file)
  *
  *   You should have received a copy of the GNU General Public License
  *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
  * Copyright 2001  hereUare Communications, Inc. <raghud@hereuare.com>
+ * Copyright 2006  The FreeRADIUS server project
  */
+
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
+
 #include "eap_tls.h"
 
 #ifndef NO_OPENSSL
@@ -27,6 +32,11 @@ void cbtls_info(const SSL *s, int where, int ret)
 {
        const char *str, *state;
        int w;
+       EAP_HANDLER *handler = (EAP_HANDLER *)SSL_get_ex_data(s, 0);
+       REQUEST *request = NULL;
+       char buffer[1024];
+
+       if (handler) request = handler->request;
 
        w = where & ~SSL_ST_MASK;
        if (w & SSL_ST_CONNECT) str="    TLS_connect";
@@ -35,157 +45,49 @@ void cbtls_info(const SSL *s, int where, int ret)
 
        state = SSL_state_string_long(s);
        state = state ? state : "NULL";
+       buffer[0] = '\0';
 
        if (where & SSL_CB_LOOP) {
-               DEBUG2("%s: %s\n", str, state);
+               RDEBUG2("%s: %s\n", str, state);
        } else if (where & SSL_CB_HANDSHAKE_START) {
-               DEBUG2("%s: %s\n", str, state);
+               RDEBUG2("%s: %s\n", str, state);
        } else if (where & SSL_CB_HANDSHAKE_DONE) {
-               DEBUG2("%s: %s\n", str, state);
+               RDEBUG2("%s: %s\n", str, state);
        } else if (where & SSL_CB_ALERT) {
                str=(where & SSL_CB_READ)?"read":"write";
-               radlog(L_ERR,"TLS Alert %s:%s:%s\n", str,
-                       SSL_alert_type_string_long(ret),
-                       SSL_alert_desc_string_long(ret));
-       } else if (where & SSL_CB_EXIT) {
-               if (ret == 0)
-                       radlog(L_ERR, "%s:failed in %s\n", str, state);
-               else if (ret < 0)
-                       radlog(L_ERR, "%s:error in %s\n", str, state);
-       }
-}
-
-/*
- *     Before trusting a certificate, you must make sure that the
- *     certificate is 'valid'. There are several steps that your
- *     application can take in determining if a certificate is
- *     valid. Commonly used steps are:
- *
- *     1.Verifying the certificate's signature, and verifying that
- *     the certificate has been issued by a trusted Certificate
- *     Authority.
- *
- *     2.Verifying that the certificate is valid for the present date
- *     (i.e. it is being presented within its validity dates).
- *
- *     3.Verifying that the certificate has not been revoked by its
- *     issuing Certificate Authority, by checking with respect to a
- *     Certificate Revocation List (CRL).
- *
- *     4.Verifying that the credentials presented by the certificate
- *     fulfill additional requirements specific to the application,
- *     such as with respect to access control lists or with respect
- *     to OCSP (Online Certificate Status Processing).
- *
- *     NOTE: This callback will be called multiple times based on the
- *     depth of the root certificate chain
- */
-int cbtls_verify(int ok, X509_STORE_CTX *ctx)
-{
-       char subject[256]; /* Used for the subject name */
-       char issuer[256]; /* Used for the issuer name */
-       char buf[256];
-       char cn_str[256];
-       EAP_HANDLER *handler = NULL;
-       X509 *client_cert;
-       SSL *ssl;
-       int err, depth;
-       EAP_TLS_CONF *conf;
-       int my_ok = ok;
-
-       client_cert = X509_STORE_CTX_get_current_cert(ctx);
-       err = X509_STORE_CTX_get_error(ctx);
-       depth = X509_STORE_CTX_get_error_depth(ctx);
-
-       if (!my_ok) {
-               radlog(L_ERR,"--> verify error:num=%d:%s\n",err,
-                       X509_verify_cert_error_string(err));
-               return my_ok;
-       }
-       /*
-        *      Catch too long Certificate chains
-        */
 
-       /*
-        * Retrieve the pointer to the SSL of the connection currently treated
-        * and the application specific data stored into the SSL object.
-        */
-       ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
-       handler = (EAP_HANDLER *)SSL_get_ex_data(ssl, 0);
-       conf = (EAP_TLS_CONF *)SSL_get_ex_data(ssl, 1);
-
-       /*
-        *      Get the Subject & Issuer
-        */
-       subject[0] = issuer[0] = '\0';
-       X509_NAME_oneline(X509_get_subject_name(client_cert), subject, 256);
-       X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), issuer, 256);
-
-       /*
-        *      Get the Common Name
-        */
-       X509_NAME_get_text_by_NID(X509_get_subject_name(client_cert),
-             NID_commonName, buf, 256);
-
-       switch (ctx->error) {
-
-       case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
-               radlog(L_ERR, "issuer= %s\n", issuer);
-               break;
-       case X509_V_ERR_CERT_NOT_YET_VALID:
-       case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
-               radlog(L_ERR, "notBefore=");
-#if 0
-               ASN1_TIME_print(bio_err, X509_get_notBefore(ctx->current_cert));
-#endif
-               break;
-       case X509_V_ERR_CERT_HAS_EXPIRED:
-       case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
-               radlog(L_ERR, "notAfter=");
-#if 0
-               ASN1_TIME_print(bio_err, X509_get_notAfter(ctx->current_cert));
-#endif
-               break;
-       }
-
-       /*
-        *      If we're at the actual client cert and the conf tells
-        *      us to, check the CN in the cert against the xlat'ed
-        *      value
-        */
-       if (depth == 0 && conf->check_cert_cn != NULL) {
-               if (!radius_xlat(cn_str, sizeof(cn_str), conf->check_cert_cn, handler->request, NULL)) {
-                       radlog(L_ERR, "rlm_eap_tls (%s): xlat failed.",
-                               conf->check_cert_cn);
-                       /* if this fails, fail the verification */
-                       my_ok = 0;
-               }
-               DEBUG2("    rlm_eap_tls: checking certificate CN (%s) with xlat'ed value (%s)", buf, cn_str);
-               if (strncmp(cn_str, buf, sizeof(buf)) != 0) {
-                       my_ok = 0;
-                       radlog(L_AUTH, "rlm_eap_tls: Certificate CN (%s) does not match specified value (%s)!", buf, cn_str);
+               snprintf(buffer, sizeof(buffer), "TLS Alert %s:%s:%s\n",
+                        str,
+                        SSL_alert_type_string_long(ret),
+                        SSL_alert_desc_string_long(ret));
+       } else if (where & SSL_CB_EXIT) {
+               if (ret == 0) {
+                       snprintf(buffer, sizeof(buffer), "%s: failed in %s",
+                                str, state);
+
+               } else if (ret < 0) {
+                       if (SSL_want_read(s)) {
+                               RDEBUG2("%s: Need to read more data: %s",
+                                      str, state);
+                       } else {
+                               snprintf(buffer, sizeof(buffer),
+                                        "%s: error in %s\n", str, state);
+                       }
                }
        }
 
-       if (debug_flag > 0) {
-               radlog(L_INFO, "chain-depth=%d, ", depth);
-               /*
-                 if (depth > 0) {
-                 return ok;
-                 }
-               */
-               radlog(L_INFO, "error=%d", err);
-
-               radlog(L_INFO, "--> User-Name = %s", handler->identity);
-               radlog(L_INFO, "--> BUF-Name = %s", buf);
-               radlog(L_INFO, "--> subject = %s", subject);
-               radlog(L_INFO, "--> issuer  = %s", issuer);
-               radlog(L_INFO, "--> verify return:%d", my_ok);
+       if (buffer[0]) {
+               radlog(L_ERR, "%s", buffer);
+               
+               if (request) {
+                       VALUE_PAIR *vp;
+                       
+                       vp = pairmake("Module-Failure-Message", buffer, T_OP_ADD);
+                       if (vp) pairadd(&request->packet->vps, vp);
+               }
        }
-       return my_ok;
 }
 
-
 /*
  *     Fill in our 'info' with TLS data.
  */
@@ -195,6 +97,12 @@ void cbtls_msg(int write_p, int msg_version, int content_type,
 {
        tls_session_t *state = (tls_session_t *)arg;
 
+       /*
+        *      Work around bug #298, where we may be called with a NULL
+        *      argument.  We should really log a serious error
+        */
+       if (!arg) return;
+
        state->info.origin = (unsigned char)write_p;
        state->info.content_type = (unsigned char)content_type;
        state->info.record_len = len;
@@ -223,15 +131,11 @@ int cbtls_password(char *buf,
        return(strlen((char *)userdata));
 }
 
-RSA *cbtls_rsa(SSL *s UNUSED, int is_export UNUSED, int keylength)
-{
-       static RSA *rsa_tmp=NULL;
-
-       if (rsa_tmp == NULL) {
-               DEBUG2("Generating temp (%d bit) RSA key...", keylength);
-               rsa_tmp=RSA_generate_key(keylength, RSA_F4, NULL, NULL);
-       }
-       return(rsa_tmp);
-}
+/*
+ *     For callbacks
+ */
+int eaptls_handle_idx = -1;
+int eaptls_conf_idx = -1;
+int eaptls_session_idx = -1;
 
 #endif /* !defined(NO_OPENSSL) */