From: Alan T. DeKok Date: Tue, 3 Aug 2010 12:37:36 +0000 (+0200) Subject: Be moe forgiving about the Digest attributes. X-Git-Tag: release_3_0_0_beta0~1321 X-Git-Url: http://www.project-moonshot.org/gitweb/?a=commitdiff_plain;ds=sidebyside;h=5bf5f95943748d82fac541e7cda2b75467f6b73c;p=freeradius.git Be moe forgiving about the Digest attributes. In the "authorize" section, check if the attributes exist, and are properly formatted. If not, return NOOP. If so, decode them, and set Auth-Type := digest If they don't list "digest" in "authorize", decode the attributes in the "authenticate" section, too. --- diff --git a/src/modules/rlm_digest/rlm_digest.c b/src/modules/rlm_digest/rlm_digest.c index 9013c0a..6d84eea 100644 --- a/src/modules/rlm_digest/rlm_digest.c +++ b/src/modules/rlm_digest/rlm_digest.c @@ -27,13 +27,10 @@ RCSID("$Id$") #include #include -static int digest_authorize(void *instance, REQUEST *request) +static int digest_fix(REQUEST *request) { VALUE_PAIR *vp; - /* quiet the compiler */ - instance = instance; - /* * We need both of these attributes to do the authentication. */ @@ -46,8 +43,7 @@ static int digest_authorize(void *instance, REQUEST *request) * Check the sanity of the attribute. */ if (vp->length != 32) { - RDEBUG("ERROR: Received invalid Digest-Response attribute (length %d should be 32)", vp->length); - return RLM_MODULE_INVALID; + return RLM_MODULE_NOOP; } /* @@ -55,68 +51,63 @@ static int digest_authorize(void *instance, REQUEST *request) */ vp = pairfind(request->packet->vps, PW_DIGEST_ATTRIBUTES, 0); if (vp == NULL) { - RDEBUG("ERROR: Received Digest-Response without Digest-Attributes"); - return RLM_MODULE_INVALID; + return RLM_MODULE_NOOP; } /* - * Everything's OK, add a digest authentication type. + * Check for proper format of the Digest-Attributes */ - if (pairfind(request->config_items, PW_AUTHTYPE, 0) == NULL) { - RDEBUG("Adding Auth-Type = DIGEST"); - pairadd(&request->config_items, - pairmake("Auth-Type", "DIGEST", T_OP_EQ)); - } + RDEBUG("Checking for correctly formatted Digest-Attributes"); + while (vp) { + int length = vp->length; + int attrlen; + uint8_t *p = &vp->vp_octets[0]; - return RLM_MODULE_OK; -} + /* + * Until this stupidly encoded attribute is exhausted. + */ + while (length > 0) { + /* + * The attribute type must be valid + */ + if ((p[0] == 0) || (p[0] > 10)) { + RDEBUG("Not formatted as Digest-Attributes"); + return RLM_MODULE_NOOP; + } -/* - * Perform all of the wondrous variants of digest authentication. - */ -static int digest_authenticate(void *instance, REQUEST *request) -{ - int i; - size_t a1_len, a2_len, kd_len; - uint8_t a1[(MAX_STRING_LEN + 1) * 5]; /* can be 5 attributes */ - uint8_t a2[(MAX_STRING_LEN + 1) * 3]; /* can be 3 attributes */ - uint8_t kd[(MAX_STRING_LEN + 1) * 5]; - uint8_t hash[16]; /* MD5 output */ - VALUE_PAIR *vp, *passwd, *algo; - VALUE_PAIR *qop, *nonce; + attrlen = p[1]; /* stupid VSA format */ - instance = instance; /* -Wunused */ + /* + * Too short. + */ + if (attrlen < 3) { + RDEBUG("Not formatted as Digest-Attributes"); + return RLM_MODULE_NOOP; + } - /* - * We require access to the plain-text password. - */ - passwd = pairfind(request->config_items, PW_DIGEST_HA1, 0); - if (passwd) { - if (passwd->length != 32) { - radlog_request(L_AUTH, 0, request, "Digest-HA1 has invalid length, authentication failed."); - return RLM_MODULE_INVALID; - } - } else { - passwd = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0); - } - if (!passwd) { - radlog_request(L_AUTH, 0, request, "Cleartext-Password or Digest-HA1 is required for authentication."); - return RLM_MODULE_INVALID; - } + /* + * Too long. + */ + if (attrlen > length) { + RDEBUG("Not formatted as Digest-Attributes"); + return RLM_MODULE_NOOP; + } - /* - * We need these, too. - */ - vp = pairfind(request->packet->vps, PW_DIGEST_ATTRIBUTES, 0); - if (vp == NULL) { - RDEBUG("ERROR: You set 'Auth-Type = Digest' for a request that did not contain any digest attributes!"); - return RLM_MODULE_INVALID; + length -= attrlen; + p += attrlen; + } /* loop over this one attribute */ + + /* + * Find the next one, if it exists. + */ + vp = pairfind(vp->next, PW_DIGEST_ATTRIBUTES, 0); } /* - * Loop through the Digest-Attributes, sanity checking them. + * Convert them to something sane. */ - RDEBUG(" rlm_digest: Converting Digest-Attributes to something sane..."); + RDEBUG("Digest-Attributes look OK. Converting them to something more usful."); + vp = pairfind(request->packet->vps, PW_DIGEST_ATTRIBUTES, 0); while (vp) { int length = vp->length; int attrlen; @@ -124,7 +115,7 @@ static int digest_authenticate(void *instance, REQUEST *request) VALUE_PAIR *sub; /* - * Until this stupidly encoded attribure is exhausted. + * Until this stupidly encoded attribute is exhausted. */ while (length > 0) { /* @@ -160,8 +151,8 @@ static int digest_authenticate(void *instance, REQUEST *request) * Didn't they know that VSA's exist? */ sub = radius_paircreate(request, &request->packet->vps, - PW_DIGEST_REALM - 1 + p[0], - 0, PW_TYPE_STRING); + PW_DIGEST_REALM - 1 + p[0], 0, + PW_TYPE_STRING); memcpy(&sub->vp_octets[0], &p[2], attrlen - 2); sub->vp_octets[attrlen - 2] = '\0'; sub->length = attrlen - 2; @@ -187,6 +178,99 @@ static int digest_authenticate(void *instance, REQUEST *request) vp = pairfind(vp->next, PW_DIGEST_ATTRIBUTES, 0); } + return RLM_MODULE_OK; +} + +static int digest_authorize(void *instance, REQUEST *request) +{ + int rcode; + + /* quiet the compiler */ + instance = instance; + + /* + * Double-check and fix the attributes. + */ + rcode = digest_fix(request); + if (rcode != RLM_MODULE_OK) return rcode; + + /* + * Everything's OK, add a digest authentication type. + */ + if (pairfind(request->config_items, PW_AUTHTYPE, 0) == NULL) { + RDEBUG("Adding Auth-Type = DIGEST"); + pairadd(&request->config_items, + pairmake("Auth-Type", "DIGEST", T_OP_EQ)); + } + + return RLM_MODULE_OK; +} + +/* + * Perform all of the wondrous variants of digest authentication. + */ +static int digest_authenticate(void *instance, REQUEST *request) +{ + int i; + size_t a1_len, a2_len, kd_len; + uint8_t a1[(MAX_STRING_LEN + 1) * 5]; /* can be 5 attributes */ + uint8_t a2[(MAX_STRING_LEN + 1) * 3]; /* can be 3 attributes */ + uint8_t kd[(MAX_STRING_LEN + 1) * 5]; + uint8_t hash[16]; /* MD5 output */ + VALUE_PAIR *vp, *passwd, *algo; + VALUE_PAIR *qop, *nonce; + + instance = instance; /* -Wunused */ + + /* + * We require access to the plain-text password, or to the + * Digest-HA1 parameter. + */ + passwd = pairfind(request->config_items, PW_DIGEST_HA1, 0); + if (passwd) { + if (passwd->length != 32) { + radlog_request(L_AUTH, 0, request, "Digest-HA1 has invalid length, authentication failed."); + return RLM_MODULE_INVALID; + } + } else { + passwd = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0); + } + if (!passwd) { + radlog_request(L_AUTH, 0, request, "Cleartext-Password or Digest-HA1 is required for authentication."); + return RLM_MODULE_INVALID; + } + + /* + * We need these, too. + */ + vp = pairfind(request->packet->vps, PW_DIGEST_ATTRIBUTES, 0); + if (vp == NULL) { + error: + RDEBUG("ERROR: You set 'Auth-Type = Digest' for a request that did not contain any digest attributes!w"); + return RLM_MODULE_INVALID; + } + + /* + * Look for the "internal" FreeRADIUS Digest attributes. + * If they don't exist, it means that someone forced + * Auth-Type = digest, without putting "digest" into the + * "authorize" section. In that case, try to decode the + * attributes here. + */ + if (!pairfind(request->packet->vps, PW_DIGEST_NONCE, 0)) { + int rcode; + + rcode = digest_fix(request); + + /* + * NOOP means "couldn't find the attributes". + * That's bad. + */ + if (rcode == RLM_MODULE_NOOP) goto error; + + if (rcode != RLM_MODULE_OK) return rcode; + } + /* * We require access to the Digest-Nonce-Value */