*
* 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.
*/
/*
#include "otp.h"
#ifdef FREERADIUS
-#include "modules.h"
+#include <modules.h>
#endif
static const char rcsid[] = "$Id$";
offsetof(otp_option_t, mschap_mppe_policy), NULL, "2" },
{ "mschap_mppe_bits", PW_TYPE_INTEGER,
offsetof(otp_option_t, mschap_mppe_types), NULL, "2" },
-#if 0
- { "twindow_min", PW_TYPE_INTEGER, offsetof(otp_option_t, twindow_min),
- NULL, "0" },
- { "twindow_max", PW_TYPE_INTEGER, offsetof(otp_option_t, twindow_max),
- NULL, "0" },
-#endif
+
+ { "debug", PW_TYPE_BOOLEAN, offsetof(otp_option_t, debug),
+ NULL, "no" },
{ NULL, -1, 0, NULL, NULL } /* end the list */
};
static int
otp_instantiate(CONF_SECTION *conf, void **instance)
{
+ const char *log_prefix = OTP_MODULE_NAME;
otp_option_t *opt;
char *p;
/* Onetime initialization. */
if (!ninstance) {
/* Generate a random key, used to protect the State attribute. */
- if (otp_get_random(-1, hmac_key, sizeof(hmac_key)) == -1) {
- otp_log(OTP_LOG_ERR, "failed to obtain random data for hmac_key");
+ if (otp_get_random(-1, hmac_key, sizeof(hmac_key), log_prefix) == -1) {
+ otp_log(OTP_LOG_ERR, "%s: %s: failed to obtain random data for hmac_key",
+ log_prefix, __func__);
free(opt);
return -1;
}
if ((opt->chal_len < 5) || (opt->chal_len > OTP_MAX_CHALLENGE_LEN)) {
opt->chal_len = 6;
otp_log(OTP_LOG_ERR,
- "invalid challenge_length, range 5-%d, using default of 6",
- OTP_MAX_CHALLENGE_LEN);
+ "%s: %s: invalid challenge_length, range 5-%d, using default of 6",
+ log_prefix, __func__, OTP_MAX_CHALLENGE_LEN);
}
/* Enforce a single "%" sequence, which must be "%s" */
strncmp(p,"%s",2)) {
free(opt->chal_prompt);
opt->chal_prompt = strdup(OTP_CHALLENGE_PROMPT);
- otp_log(OTP_LOG_ERR, "invalid challenge_prompt, using default of \"%s\"",
- OTP_CHALLENGE_PROMPT);
+ otp_log(OTP_LOG_ERR,
+ "%s: %s: invalid challenge_prompt, using default of \"%s\"",
+ log_prefix, __func__, OTP_CHALLENGE_PROMPT);
}
if (opt->softfail < 0) {
opt->softfail = 5;
- otp_log(OTP_LOG_ERR, "softfail must be at least 1 "
- "(or 0 == infinite), using default of 5");
+ otp_log(OTP_LOG_ERR, "%s: %s: softfail must be at least 1 "
+ "(or 0 == infinite), using default of 5",
+ log_prefix, __func__);
}
if (opt->hardfail < 0) {
opt->hardfail = 0;
- otp_log(OTP_LOG_ERR, "hardfail must be at least 1 "
- "(or 0 == infinite), using default of 0");
+ otp_log(OTP_LOG_ERR, "%s: %s: hardfail must be at least 1 "
+ "(or 0 == infinite), using default of 0",
+ log_prefix, __func__);
+ }
+
+ if (!opt->hardfail && opt->hardfail <= opt->softfail) {
+ /*
+ * This is noise if the admin leaves softfail alone, so it gets
+ * the default value of 5, and sets hardfail <= to that ... but
+ * in practice that will never happen. Anyway, it is easily
+ * overcome with a softfail setting of 0.
+ *
+ * This is because we can't tell the difference between a default
+ * [softfail] value and an admin-configured one.
+ */
+ otp_log(OTP_LOG_ERR, "%s: %s: hardfail (%d) is less than softfail (%d), "
+ "effectively disabling softfail",
+ log_prefix, __func__, opt->hardfail, opt->softfail);
}
if (opt->fast_sync && !opt->allow_sync) {
opt->fast_sync = 0;
- otp_log(OTP_LOG_INFO,
- "fast_sync is yes, but allow_sync is no; disabling fast_sync");
+ otp_log(OTP_LOG_ERR, "%s: %s: fast_sync is yes, but allow_sync is no; "
+ "disabling fast_sync",
+ log_prefix, __func__);
}
if (!opt->allow_sync && !opt->allow_async) {
otp_log(OTP_LOG_ERR,
- "at least one of {allow_async, allow_sync} must be set");
+ "%s: %s: at least one of {allow_async, allow_sync} must be set",
+ log_prefix, __func__);
free(opt);
return -1;
}
if ((opt->ewindow_size > OTP_MAX_EWINDOW_SIZE) ||
(opt->ewindow_size < 0)) {
opt->ewindow_size = 0;
- otp_log(OTP_LOG_ERR, "max ewindow_size is %d, using default of 0",
- OTP_MAX_EWINDOW_SIZE);
+ otp_log(OTP_LOG_ERR, "%s: %s: max ewindow_size is %d, using default of 0",
+ log_prefix, __func__, OTP_MAX_EWINDOW_SIZE);
}
if (opt->rwindow_size && (opt->rwindow_size < opt->ewindow_size)) {
opt->rwindow_size = 0;
- otp_log(OTP_LOG_ERR, "rwindow_size must be at least as large as "
- "ewindow_size, using default of 0");
+ otp_log(OTP_LOG_ERR, "%s: %s: rwindow_size must be at least as large as "
+ "ewindow_size, using default of 0",
+ log_prefix, __func__);
}
if (opt->rwindow_size && !opt->rwindow_delay) {
opt->rwindow_size = 0;
- otp_log(OTP_LOG_ERR, "rwindow_size is non-zero, "
- "but rwindow_delay is zero; disabling rwindow");
+ otp_log(OTP_LOG_ERR, "%s: %s: rwindow_size is non-zero, "
+ "but rwindow_delay is zero; disabling rwindow",
+ log_prefix, __func__);
}
if ((opt->mschapv2_mppe_policy > 2) || (opt->mschapv2_mppe_policy < 0)) {
opt->mschapv2_mppe_policy = 2;
- otp_log(OTP_LOG_ERR, "invalid value for mschapv2_mppe, using default of 2");
+ otp_log(OTP_LOG_ERR,
+ "%s: %s: invalid value for mschapv2_mppe, using default of 2",
+ log_prefix, __func__);
}
if ((opt->mschapv2_mppe_types > 2) || (opt->mschapv2_mppe_types < 0)) {
opt->mschapv2_mppe_types = 2;
otp_log(OTP_LOG_ERR,
- "invalid value for mschapv2_mppe_bits, using default of 2");
+ "%s: %s: invalid value for mschapv2_mppe_bits, using default of 2",
+ log_prefix, __func__);
}
if ((opt->mschap_mppe_policy > 2) || (opt->mschap_mppe_policy < 0)) {
opt->mschap_mppe_policy = 2;
- otp_log(OTP_LOG_ERR, "invalid value for mschap_mppe, using default of 2");
+ otp_log(OTP_LOG_ERR,
+ "%s: %s: invalid value for mschap_mppe, using default of 2",
+ log_prefix, __func__);
}
if (opt->mschap_mppe_types != 2) {
opt->mschap_mppe_types = 2;
otp_log(OTP_LOG_ERR,
- "invalid value for mschap_mppe_bits, using default of 2");
- }
-
-#if 0
- if (opt->twindow_max - opt->twindow_min > OTP_MAX_TWINDOW_SIZE) {
- opt->twindow_min = opt->twindow_max = 0;
- otp_log(OTP_LOG_ERR, "max time window size is %d, using default of 0",
- OTP_MAX_TWINDOW_SIZE);
- }
- if ((opt->twindow_min > 0) || (opt->twindow_max < 0) ||
- (opt->twindow_max < opt->twindow_min)) {
- opt->twindow_min = opt->twindow_max = 0;
- otp_log(OTP_LOG_ERR, "invalid values for time window, using default of 0");
+ "%s: %s: invalid value for mschap_mppe_bits, using default of 2",
+ log_prefix, __func__);
}
-#endif
- /* Set the instance name (for use with authorize()) */
+ /* set the instance name (for use with authorize()) */
opt->name = cf_section_name2(conf);
if (!opt->name)
opt->name = cf_section_name1(conf);
if (!opt->name) {
- otp_log(OTP_LOG_CRIT, "no instance name (this can't happen)");
+ otp_log(OTP_LOG_CRIT, "%s: %s: no instance name (this can't happen)",
+ log_prefix, __func__);
free(opt);
return -1;
}
+ /* set debug opt for portable debug output (see DEBUG definition) */
+ if (debug_flag)
+ opt->debug = 1;
+
*instance = opt;
return 0;
}
otp_authorize(void *instance, REQUEST *request)
{
otp_option_t *inst = (otp_option_t *) instance;
+ const char *log_prefix = OTP_MODULE_NAME;
char challenge[OTP_MAX_CHALLENGE_LEN + 1]; /* +1 for '\0' terminator */
char *state;
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;
}
}
/* User-Name attribute required. */
if (!request->username) {
otp_log(OTP_LOG_AUTH,
- "autz: Attribute \"User-Name\" required for authentication.");
+ "%s: %s: Attribute \"User-Name\" required for authentication.",
+ log_prefix, __func__);
return RLM_MODULE_INVALID;
}
- if ((data.pwattr = otp_pwe_present(request)) == 0) {
- otp_log(OTP_LOG_AUTH, "autz: Attribute \"User-Password\" "
- "or equivalent required for authentication.");
+ if ((data.pwattr = otp_pwe_present(request, log_prefix)) == 0) {
+ otp_log(OTP_LOG_AUTH, "%s: %s: Attribute \"User-Password\" "
+ "or equivalent required for authentication.",
+ log_prefix, __func__);
return RLM_MODULE_INVALID;
}
/* fast_sync mode (challenge only if requested) */
if (inst->fast_sync) {
- if ((!otp_pwe_cmp(&data, inst->resync_req) &&
+ if ((!otp_pwe_cmp(&data, inst->resync_req, log_prefix) &&
/* Set a bit indicating resync */ (sflags |= htonl(1))) ||
- !otp_pwe_cmp(&data, inst->chal_req)) {
+ !otp_pwe_cmp(&data, inst->chal_req, log_prefix)) {
/*
* Generate a challenge if requested. Note that we do this
* even if configuration doesn't allow async mode.
sflags |= htonl(1);
/* Generate a random challenge. */
- if (otp_get_challenge(-1, challenge, inst->chal_len) == -1) {
- otp_log(OTP_LOG_ERR, "autz: failed to obtain random challenge");
+ 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;
}
time_t now = time(NULL);
if (sizeof(now) != 4 || sizeof(long) != 4) {
- otp_log(OTP_LOG_ERR, "autz: only ILP32 arch is supported");
+ otp_log(OTP_LOG_ERR, "%s: %s: only ILP32 arch is supported",
+ log_prefix, __func__);
return RLM_MODULE_FAIL;
}
now = htonl(now);
- if (otp_gen_state(&state, NULL, challenge, sflags, now, hmac_key) != 0) {
- otp_log(OTP_LOG_ERR, "autz: failed to generate state");
+ if (otp_gen_state(&state, NULL, challenge, inst->chal_len, sflags,
+ now, hmac_key) != 0) {
+ otp_log(OTP_LOG_ERR, "%s: %s: failed to generate state",
+ log_prefix, __func__);
return RLM_MODULE_FAIL;
}
} else {
- /* x2 b/c pairmake() string->octet needs even num of digits */
- state = rad_malloc(3 + inst->chal_len * 2);
- (void) sprintf(state, "0x%s%s", challenge, challenge);
+ state = rad_malloc(5);
+ (void) sprintf(state, "0x00");
}
pairadd(&request->reply->vps, pairmake("State", state, T_OP_EQ));
free(state);
otp_authenticate(void *instance, REQUEST *request)
{
otp_option_t *inst = (otp_option_t *) instance;
+ const char *log_prefix = OTP_MODULE_NAME;
char *username;
int rc;
int resync = 0; /* resync flag for async mode */
- char challenge[OTP_MAX_CHALLENGE_LEN + 1];
+ unsigned char challenge[OTP_MAX_CHALLENGE_LEN]; /* cf. authorize() */
VALUE_PAIR *add_vps = NULL;
struct otp_pwe_cmp_t data = {
.returned_vps = &add_vps
};
+ challenge[0] = '\0'; /* initialize for otp_pw_valid() */
+
/* User-Name attribute required. */
if (!request->username) {
otp_log(OTP_LOG_AUTH,
- "auth: Attribute \"User-Name\" required for authentication.");
+ "%s: %s: Attribute \"User-Name\" required for authentication.",
+ log_prefix, __func__);
return RLM_MODULE_INVALID;
}
- username = request->username->vp_strvalue;
+ username = request->username->strvalue;
- if ((data.pwattr = otp_pwe_present(request)) == 0) {
- otp_log(OTP_LOG_AUTH, "auth: Attribute \"User-Password\" "
- "or equivalent required for authentication.");
+ if ((data.pwattr = otp_pwe_present(request, log_prefix)) == 0) {
+ otp_log(OTP_LOG_AUTH, "%s: %s: Attribute \"User-Password\" "
+ "or equivalent required for authentication.",
+ log_prefix, __func__);
return RLM_MODULE_INVALID;
}
OTP_MODULE_NAME, T_OP_EQ));
/* Retrieve the challenge (from State attribute). */
- challenge[0] = '\0';
{
VALUE_PAIR *vp;
unsigned char *state;
int32_t sflags = 0; /* state flags */
- time_t then; /* state timestamp */
+ int32_t then; /* state timestamp */
if ((vp = pairfind(request->packet->vps, PW_STATE)) != NULL) {
- int e_length = inst->chal_len;
+ int e_length;
- /* 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 + 4 + 4 + 16; /* see otp_gen_state() */
+ else
+ e_length = 1;
if (vp->length != e_length) {
- otp_log(OTP_LOG_AUTH, "auth: bad state for [%s]: length", username);
+ otp_log(OTP_LOG_AUTH, "%s: %s: bad state for [%s]: length",
+ log_prefix, __func__, username);
return RLM_MODULE_INVALID;
}
if (inst->allow_async) {
/* Verify the state. */
- (void) memset(challenge, 0, sizeof(challenge));
- (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);
- if (otp_gen_state(NULL, &state, challenge,
+ (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);
+ if (otp_gen_state(NULL, &state, challenge, inst->chal_len,
sflags, then, hmac_key) != 0) {
- otp_log(OTP_LOG_ERR, "auth: failed to generate state");
+ 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)) {
- otp_log(OTP_LOG_AUTH, "auth: bad state for [%s]: hmac", username);
+ 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);
return RLM_MODULE_REJECT;
}
/* State is valid, but check expiry. */
then = ntohl(then);
if (time(NULL) - then > inst->chal_delay) {
- otp_log(OTP_LOG_AUTH, "auth: bad state for [%s]: expired", username);
+ otp_log(OTP_LOG_AUTH, "%s: %s: bad state for [%s]: expired",
+ log_prefix, __func__, username);
return RLM_MODULE_REJECT;
}
resync = ntohl(sflags) & 1;
/* do it */
rc = otprc2rlmrc(otp_pw_valid(username, challenge, NULL, resync, inst,
- otp_pwe_cmp, &data, "auth"));
+ otp_pwe_cmp, &data, log_prefix));
/* Handle any vps returned from otp_pwe_cmp(). */
if (rc == RLM_MODULE_OK) {
* 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 */
};