import from HEAD:
[freeradius.git] / src / modules / rlm_otp / otp_rlm.c
index ba6557b..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>
@@ -55,8 +50,8 @@
 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" },
 
@@ -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,
@@ -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,16 +496,33 @@ otp_authenticate(void *instance, REQUEST *request)
       }
 
       if (inst->allow_async) {
-        /* Verify the state. */
-        (void) memcpy(challenge, vp->strvalue, inst->chal_len);
-        (void) memcpy(&sflags, vp->strvalue + inst->chal_len, 4);
-        (void) memcpy(&then, 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;
         }
+        /* 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);