*
* 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[] = {
{ "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" },
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;
}
}
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;
* 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) {
}
} 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);
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));
.returned_vps = &add_vps
};
+ challenge[0] = '\0'; /* initialize for otp_pw_valid() */
+
/* User-Name attribute required. */
if (!request->username) {
otp_log(OTP_LOG_AUTH,
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\" "
{
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",
}
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);
* 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 */
NULL, /* post-proxy */
NULL /* post-auth */
},
+ otp_detach, /* detach */
+ NULL, /* destroy */
};