import from HEAD:
[freeradius.git] / src / modules / rlm_otp / otp_rlm.c
index bda67ec..7831d0f 100644 (file)
@@ -18,7 +18,7 @@
  *
  * Copyright 2000,2001,2002  The FreeRADIUS server project
  * Copyright 2001,2002  Google, Inc.
- * Copyright 2005 TRI-D Systems, Inc.
+ * Copyright 2005,2006 TRI-D Systems, Inc.
  */
 
 /*
  * Please read the accompanying docs.
  */
 
-/*
- * TODO: support setting multiple auth-types in authorize()
- * TODO: support other than ILP32 (for State)
- */
-
 
 #include <stdlib.h>
 #include <string.h>
 
 #include "otp.h"
 #ifdef FREERADIUS
-#include "modules.h"
+#include <modules.h>
 #endif
 
 static const char rcsid[] = "$Id$";
 
 /* Global data */
-static unsigned char hmac_key[16];     /* to protect State attribute     */
-static int ninstance = 0;              /* #instances, for global init    */
+static unsigned char hmac_key[16];     /* to protect State attribute  */
+static int ninstance = 0;              /* #instances, for global init */
 
 /* A mapping of configuration file names to internal variables. */
 static const CONF_PARSER module_config[] = {
@@ -101,6 +96,8 @@ static const CONF_PARSER module_config[] = {
   { "mschap_mppe_bits", PW_TYPE_INTEGER,
     offsetof(otp_option_t, mschap_mppe_types), NULL, "2" },
 
+  { "site_transform", PW_TYPE_BOOLEAN, offsetof(otp_option_t, site_transform),
+    NULL, "yes" },
   { "debug", PW_TYPE_BOOLEAN, offsetof(otp_option_t, debug),
     NULL, "no" },
 
@@ -320,7 +317,7 @@ otp_authorize(void *instance, REQUEST *request)
     auth_type_found = 0;
     if ((vp = pairfind(request->config_items, PW_AUTHTYPE)) != NULL) {
       auth_type_found = 1;
-      if (strcmp(vp->vp_strvalue, inst->name))
+      if (strcmp(vp->strvalue, inst->name))
         return RLM_MODULE_NOOP;
     }
   }
@@ -373,7 +370,7 @@ gen_challenge:
     sflags |= htonl(1);
 
   /* Generate a random challenge. */
-  if (otp_get_challenge(-1, challenge, inst->chal_len, log_prefix) == -1) {
+  if (otp_async_challenge(-1, challenge, inst->chal_len, log_prefix) == -1) {
     otp_log(OTP_LOG_ERR, "%s: %s: failed to obtain random challenge",
             log_prefix, __func__);
     return RLM_MODULE_FAIL;
@@ -389,14 +386,7 @@ gen_challenge:
    * otp_authenticate().
    */
   if (inst->allow_async) {
-    time_t now = time(NULL);
-
-    if (sizeof(now) != 4 || sizeof(long) != 4) {
-      otp_log(OTP_LOG_ERR, "%s: %s: only ILP32 arch is supported",
-              log_prefix, __func__);
-      return RLM_MODULE_FAIL;
-    }
-    now = htonl(now);
+    int32_t now = htonl(time(NULL));   /* low-order 32 bits on LP64 */
 
     if (otp_gen_state(&state, NULL, challenge, inst->chal_len, sflags,
                       now, hmac_key) != 0) {
@@ -406,7 +396,8 @@ gen_challenge:
     }
   } else {
     state = rad_malloc(5);
-    (void) sprintf(state, "0x00");
+    /* a non-NUL byte, so that Cisco (see otp_gen_state()) returns it */
+    (void) sprintf(state, "0x01");
   }
   pairadd(&request->reply->vps, pairmake("State", state, T_OP_EQ));
   free(state);
@@ -417,7 +408,6 @@ gen_challenge:
 
     u_challenge = rad_malloc(strlen(inst->chal_prompt) +
                              OTP_MAX_CHALLENGE_LEN + 1);
-/* XXX */
     (void) sprintf(u_challenge, inst->chal_prompt, challenge);
     pairadd(&request->reply->vps,
             pairmake("Reply-Message", u_challenge, T_OP_EQ));
@@ -458,6 +448,8 @@ otp_authenticate(void *instance, REQUEST *request)
     .returned_vps      = &add_vps
   };
 
+  challenge[0] = '\0'; /* initialize for otp_pw_valid() */
+
   /* User-Name attribute required. */
   if (!request->username) {
     otp_log(OTP_LOG_AUTH,
@@ -465,7 +457,7 @@ otp_authenticate(void *instance, REQUEST *request)
             log_prefix, __func__);
     return RLM_MODULE_INVALID;
   }
-  username = request->username->vp_strvalue;
+  username = request->username->strvalue;
 
   if ((data.pwattr = otp_pwe_present(request, log_prefix)) == 0) {
     otp_log(OTP_LOG_AUTH, "%s: %s: Attribute \"User-Password\" "
@@ -484,15 +476,18 @@ otp_authenticate(void *instance, REQUEST *request)
   {
     VALUE_PAIR *vp;
     unsigned char      *state;
-    int32_t            sflags = 0;     /* state flags */
-    int32_t            then;           /* state timestamp */
+    unsigned char      *raw_state;
+    unsigned char      *rad_state;
+    int32_t            sflags = 0;     /* state flags           */
+    int32_t            then;           /* state timestamp       */
+    int                        e_length;       /* expected State length */
 
     if ((vp = pairfind(request->packet->vps, PW_STATE)) != NULL) {
-      int e_length = inst->chal_len;
-
-      /* Extend expected length if state should have been protected. */
+      /* set expected State length */
       if (inst->allow_async)
-        e_length += 4 + 4 + 16; /* sflags + time + hmac */
+        e_length = inst->chal_len * 2 + 8 + 8 + 32; /* see otp_gen_state() */
+      else
+        e_length = 1;
 
       if (vp->length != e_length) {
         otp_log(OTP_LOG_AUTH, "%s: %s: bad state for [%s]: length",
@@ -501,17 +496,34 @@ otp_authenticate(void *instance, REQUEST *request)
       }
 
       if (inst->allow_async) {
-        /* Verify the state. */
-        (void) memcpy(challenge, vp->vp_strvalue, inst->chal_len);
-        (void) memcpy(&sflags, vp->vp_strvalue + inst->chal_len, 4);
-        (void) memcpy(&then, vp->vp_strvalue + inst->chal_len + 4, 4);
+        /*
+         * Verify the state.
+         */
+
+        rad_state = rad_malloc(e_length + 1);
+        raw_state = rad_malloc(e_length / 2);
+
+        /* ASCII decode */
+        (void) memcpy(rad_state, vp->strvalue, vp->length);
+        rad_state[e_length] = '\0';
+        (void) otp_keystring2keyblock(rad_state, raw_state);
+        free(rad_state);
+        
+        /* extract data from State */
+        (void) memcpy(challenge, raw_state, inst->chal_len);
+        (void) memcpy(&sflags, raw_state + inst->chal_len, 4);
+        (void) memcpy(&then, raw_state + inst->chal_len + 4, 4);
+        free(raw_state);
+
+        /* generate new state from returned input data */
         if (otp_gen_state(NULL, &state, challenge, inst->chal_len,
                           sflags, then, hmac_key) != 0) {
           otp_log(OTP_LOG_ERR, "%s: %s: failed to generate state",
                   log_prefix, __func__);
           return RLM_MODULE_FAIL;
         }
-        if (memcmp(state, vp->vp_strvalue, vp->length)) {
+        /* compare generated state against returned state to verify hmac */
+        if (memcmp(state, vp->strvalue, vp->length)) {
           otp_log(OTP_LOG_AUTH, "%s: %s: bad state for [%s]: hmac",
                   log_prefix, __func__, username);
           free(state);
@@ -575,11 +587,10 @@ otp_detach(void *instance)
  *     is single-threaded.
  */
 module_t rlm_otp = {
-  RLM_MODULE_INIT,
   "otp",
   RLM_TYPE_THREAD_SAFE,                /* type */
+  NULL,                                /* initialization */
   otp_instantiate,             /* instantiation */
-  otp_detach,                  /* detach */
   {
     otp_authenticate,          /* authentication */
     otp_authorize,             /* authorization */
@@ -590,4 +601,6 @@ module_t rlm_otp = {
     NULL,                      /* post-proxy */
     NULL                       /* post-auth */
   },
+  otp_detach,                  /* detach */
+  NULL,                                /* destroy */
 };