Updated Password-With-Header handling to make it more robust.
[freeradius.git] / src / modules / rlm_pap / rlm_pap.c
index 70ab418..9fa68ea 100644 (file)
@@ -161,7 +161,7 @@ static int pap_instantiate(CONF_SECTION *conf, void **instance)
                inst->name = cf_section_name1(conf);
        }
 
-       dval = dict_valbyname(PW_AUTH_TYPE, inst->name);
+       dval = dict_valbyname(PW_AUTH_TYPE, 0, inst->name);
        if (dval) {
                inst->auth_type = dval->value;
        } else {
@@ -200,7 +200,7 @@ static int decode_it(const char *src, uint8_t *dst)
 
        dst[2] = (unsigned char)(x & 255); x >>= 8;
        dst[1] = (unsigned char)(x & 255); x >>= 8;
-       dst[0] = (unsigned char)(x & 255); x >>= 8;
+       dst[0] = (unsigned char)(x & 255);
 
        return 1;
 }
@@ -240,7 +240,7 @@ static int base64_decode (const char *src, uint8_t *dst)
 /*
  *     Hex or base64 or bin auto-discovery.
  */
-static void normify(VALUE_PAIR *vp, size_t min_length)
+static void normify(REQUEST *request, VALUE_PAIR *vp, size_t min_length)
 {
        size_t decoded;
        uint8_t buffer[64];
@@ -253,7 +253,7 @@ static void normify(VALUE_PAIR *vp, size_t min_length)
        if (vp->length >= (2 * min_length)) {
                decoded = fr_hex2bin(vp->vp_strvalue, buffer, vp->length >> 1);
                if (decoded == (vp->length >> 1)) {
-                       DEBUG2("rlm_pap: Normalizing %s from hex encoding", vp->name);
+                       RDEBUG2("Normalizing %s from hex encoding", vp->name);
                        memcpy(vp->vp_octets, buffer, decoded);
                        vp->length = decoded;
                        return;
@@ -267,7 +267,7 @@ static void normify(VALUE_PAIR *vp, size_t min_length)
        if ((vp->length * 3) >= ((min_length * 4))) {
                decoded = base64_decode(vp->vp_strvalue, buffer);
                if (decoded >= min_length) {
-                       DEBUG2("rlm_pap: Normalizing %s from base64 encoding", vp->name);
+                       RDEBUG2("Normalizing %s from base64 encoding", vp->name);
                        memcpy(vp->vp_octets, buffer, decoded);
                        vp->length = decoded;
                        return;
@@ -313,19 +313,41 @@ static int pap_authorize(void *instance, REQUEST *request)
                {
                        int attr;
                        char *p, *q;
-                       char buffer[64];
+                       char buffer[128];
                        VALUE_PAIR *new_vp;
 
                        found_pw = TRUE;
+               redo:
                        q = vp->vp_strvalue;
                        p = strchr(q + 1, '}');
                        if (!p) {
+                               int decoded;
+
+                               /*
+                                *      Password already exists: use
+                                *      that instead of this one.
+                                */
+                               if (pairfind(request->config_items, PW_USER_PASSWORD) ||
+                                   pairfind(request->config_items, PW_CLEARTEXT_PASSWORD)) {
+                                       RDEBUG("Config already contains \"known good\" password.  Ignoring Password-With-Header");
+                                       break;
+                               }
+
                                /*
-                                *      FIXME: Turn it into a
-                                *      cleartext-password, unless it,
-                                *      or user-password already
-                                *      exists.
+                                *      If it's binary, it may be
+                                *      base64 encoded.  Decode it,
+                                *      and re-write the attribute to
+                                *      have the decoded value.
                                 */
+                               decoded = base64_decode(vp->vp_strvalue, buffer);
+                               if ((decoded > 0) && (buffer[0] == '{') &&
+                                   (strchr(buffer, '}') != NULL)) {
+                                       memcpy(vp->vp_octets, buffer, decoded);
+                                       vp->length = decoded;
+                                       goto redo;
+                               }
+
+                               RDEBUG("Failed to decode Password-With-Header = \"%s\"", vp->vp_strvalue);
                                break;
                        }
 
@@ -336,15 +358,21 @@ static int pap_authorize(void *instance, REQUEST *request)
 
                        attr = fr_str2int(header_names, buffer, 0);
                        if (!attr) {
-                               DEBUG2("rlm_pap: Found unknown header {%s}: Not doing anything", buffer);
+                               RDEBUG2("Found unknown header {%s}: Not doing anything", buffer);
                                break;
                        }
 
                        new_vp = radius_paircreate(request,
                                                   &request->config_items,
-                                                  attr, PW_TYPE_STRING);
-                       strcpy(new_vp->vp_strvalue, p + 1);/* bounds OK */
-                       new_vp->length = strlen(new_vp->vp_strvalue);
+                                                  attr, 0, PW_TYPE_STRING);
+                       
+                       /*
+                        *      The data after the '}' may be binary,
+                        *      so we copy it via memcpy.
+                        */
+                       new_vp->length = vp->length;
+                       new_vp->length -= (p - q + 1);
+                       memcpy(new_vp->vp_strvalue, p + 1, new_vp->length);
 
                        /*
                         *      May be old-style User-Password with header.
@@ -352,7 +380,7 @@ static int pap_authorize(void *instance, REQUEST *request)
                         *      attribute, so we should delete the old
                         *      User-Password here.
                         */
-                       pairdelete(&request->config_items, PW_USER_PASSWORD);
+                       pairdelete(&request->config_items, PW_USER_PASSWORD, 0);
                }
                        break;
 
@@ -366,13 +394,13 @@ static int pap_authorize(void *instance, REQUEST *request)
                case PW_SMD5_PASSWORD:
                case PW_NT_PASSWORD:
                case PW_LM_PASSWORD:
-                       normify(vp, 16); /* ensure it's in the right format */
+                       normify(request, vp, 16); /* ensure it's in the right format */
                        found_pw = TRUE;
                        break;
 
                case PW_SHA_PASSWORD:
                case PW_SSHA_PASSWORD:
-                       normify(vp, 20); /* ensure it's in the right format */
+                       normify(request, vp, 20); /* ensure it's in the right format */
                        found_pw = TRUE;
                        break;
 
@@ -416,15 +444,15 @@ static int pap_authorize(void *instance, REQUEST *request)
                 *      Likely going to be proxied.  Avoid printing
                 *      warning message.
                 */
-               if (pairfind(request->config_items, PW_REALM) ||
-                   (pairfind(request->config_items, PW_PROXY_TO_REALM))) {
+               if (pairfind(request->config_items, PW_REALM, 0) ||
+                   (pairfind(request->config_items, PW_PROXY_TO_REALM, 0))) {
                        return RLM_MODULE_NOOP;
                }
 
                /*
                 *      The TLS types don't need passwords.
                 */
-               vp = pairfind(request->packet->vps, PW_EAP_TYPE);
+               vp = pairfind(request->packet->vps, PW_EAP_TYPE, 0);
                if (vp &&
                    ((vp->vp_integer == 13) || /* EAP-TLS */
                     (vp->vp_integer == 21) || /* EAP-TTLS */
@@ -432,7 +460,7 @@ static int pap_authorize(void *instance, REQUEST *request)
                        return RLM_MODULE_NOOP;
                }
 
-               DEBUG("rlm_pap: WARNING! No \"known good\" password found for the user.  Authentication may fail because of this.");
+               RDEBUG("WARNING! No \"known good\" password found for the user.  Authentication may fail because of this.");
                return RLM_MODULE_NOOP;
        }
 
@@ -440,7 +468,7 @@ static int pap_authorize(void *instance, REQUEST *request)
         *      Don't touch existing Auth-Types.
         */
        if (auth_type) {
-               DEBUG2("rlm_pap: Found existing Auth-Type, not changing it.");
+               RDEBUG2("Found existing Auth-Type, not changing it.");
                return RLM_MODULE_NOOP;
        }
 
@@ -457,13 +485,13 @@ static int pap_authorize(void *instance, REQUEST *request)
                        return RLM_MODULE_NOOP;
                }
 
-               DEBUG2("rlm_pap: No clear-text password in the request.  Not performing PAP.");
+               RDEBUG2("No clear-text password in the request.  Not performing PAP.");
                return RLM_MODULE_NOOP;
        }
 
        if (inst->auth_type) {
                vp = radius_paircreate(request, &request->config_items,
-                                      PW_AUTH_TYPE, PW_TYPE_INTEGER);
+                                      PW_AUTH_TYPE, 0, PW_TYPE_INTEGER);
                vp->vp_integer = inst->auth_type;
        }
 
@@ -488,7 +516,7 @@ static int pap_authenticate(void *instance, REQUEST *request)
        int scheme = PAP_ENC_INVALID;
 
        if (!request->password){
-               radlog(L_AUTH, "rlm_pap: Attribute \"Password\" is required for authentication.");
+               radlog_request(L_AUTH, 0, request, "Attribute \"Password\" is required for authentication.");
                return RLM_MODULE_INVALID;
        }
 
@@ -496,7 +524,7 @@ static int pap_authenticate(void *instance, REQUEST *request)
         *      Clear-text passwords are the only ones we support.
         */
        if (request->password->attribute != PW_USER_PASSWORD) {
-               radlog(L_AUTH, "rlm_pap: Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->name);
+               radlog_request(L_AUTH, 0, request, "Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->name);
                return RLM_MODULE_INVALID;
        }
 
@@ -510,7 +538,7 @@ static int pap_authenticate(void *instance, REQUEST *request)
                return RLM_MODULE_INVALID;
        }
 
-       DEBUG("rlm_pap: login attempt with password \"%s\"",
+       RDEBUG("login attempt with password \"%s\"",
              request->password->vp_strvalue);
 
        /*
@@ -555,21 +583,21 @@ static int pap_authenticate(void *instance, REQUEST *request)
                }
 
        fail:
-               DEBUG("rlm_pap: No password configured for the user.  Cannot do authentication");
+               RDEBUG("No password configured for the user.  Cannot do authentication");
                return RLM_MODULE_FAIL;
 
        } else {
                vp = NULL;
 
                if (inst->sch == PAP_ENC_CRYPT) {
-                       vp = pairfind(request->config_items, PW_CRYPT_PASSWORD);
+                       vp = pairfind(request->config_items, PW_CRYPT_PASSWORD, 0);
                }
 
                /*
                 *      Old-style: all passwords are in User-Password.
                 */
                if (!vp) {
-                       vp = pairfind(request->config_items, PW_USER_PASSWORD);
+                       vp = pairfind(request->config_items, PW_USER_PASSWORD, 0);
                        if (!vp) goto fail;
                }
        }
@@ -580,7 +608,7 @@ static int pap_authenticate(void *instance, REQUEST *request)
        switch (scheme) {
        case PAP_ENC_CLEAR:
        do_clear:
-               DEBUG("rlm_pap: Using clear text password \"%s\"",
+               RDEBUG("Using clear text password \"%s\"",
                      vp->vp_strvalue);
                if (strcmp((char *) vp->vp_strvalue,
                           (char *) request->password->vp_strvalue) != 0){
@@ -588,13 +616,13 @@ static int pap_authenticate(void *instance, REQUEST *request)
                        goto make_msg;
                }
        done:
-               DEBUG("rlm_pap: User authenticated successfully");
+               RDEBUG("User authenticated successfully");
                return RLM_MODULE_OK;
                break;
 
        case PAP_ENC_CRYPT:
        do_crypt:
-               DEBUG("rlm_pap: Using CRYPT encryption.");
+               RDEBUG("Using CRYPT encryption.");
                if (fr_crypt_check((char *) request->password->vp_strvalue,
                                     (char *) vp->vp_strvalue) != 0) {
                        snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: CRYPT password check failed");
@@ -605,11 +633,11 @@ static int pap_authenticate(void *instance, REQUEST *request)
 
        case PW_MD5_PASSWORD:
        do_md5:
-               DEBUG("rlm_pap: Using MD5 encryption.");
+               RDEBUG("Using MD5 encryption.");
 
-               normify(vp, 16);
+               normify(request, vp, 16);
                if (vp->length != 16) {
-               DEBUG("rlm_pap: Configured MD5 password has incorrect length");
+               RDEBUG("Configured MD5 password has incorrect length");
                        snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: Configured MD5 password has incorrect length");
                        goto make_msg;
                }
@@ -627,11 +655,11 @@ static int pap_authenticate(void *instance, REQUEST *request)
 
        case PW_SMD5_PASSWORD:
        do_smd5:
-               DEBUG("rlm_pap: Using SMD5 encryption.");
+               RDEBUG("Using SMD5 encryption.");
 
-               normify(vp, 16);
+               normify(request, vp, 16);
                if (vp->length <= 16) {
-                       DEBUG("rlm_pap: Configured SMD5 password has incorrect length");
+                       RDEBUG("Configured SMD5 password has incorrect length");
                        snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: Configured SMD5 password has incorrect length");
                        goto make_msg;
                }
@@ -654,11 +682,11 @@ static int pap_authenticate(void *instance, REQUEST *request)
 
        case PW_SHA_PASSWORD:
        do_sha:
-               DEBUG("rlm_pap: Using SHA1 encryption.");
+               RDEBUG("Using SHA1 encryption.");
 
-               normify(vp, 20);
+               normify(request, vp, 20);
                if (vp->length != 20) {
-                       DEBUG("rlm_pap: Configured SHA1 password has incorrect length");
+                       RDEBUG("Configured SHA1 password has incorrect length");
                        snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: Configured SHA1 password has incorrect length");
                        goto make_msg;
                }
@@ -676,11 +704,11 @@ static int pap_authenticate(void *instance, REQUEST *request)
 
        case PW_SSHA_PASSWORD:
        do_ssha:
-               DEBUG("rlm_pap: Using SSHA encryption.");
+               RDEBUG("Using SSHA encryption.");
 
-               normify(vp, 20);
+               normify(request, vp, 20);
                if (vp->length <= 20) {
-                       DEBUG("rlm_pap: Configured SSHA password has incorrect length");
+                       RDEBUG("Configured SSHA password has incorrect length");
                        snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: Configured SHA password has incorrect length");
                        goto make_msg;
                }
@@ -700,19 +728,19 @@ static int pap_authenticate(void *instance, REQUEST *request)
 
        case PW_NT_PASSWORD:
        do_nt:
-               DEBUG("rlm_pap: Using NT encryption.");
+               RDEBUG("Using NT encryption.");
 
-               normify(vp, 16);
+               normify(request, vp, 16);
                if (vp->length != 16) {
-                       DEBUG("rlm_pap: Configured NT-Password has incorrect length");
+                       RDEBUG("Configured NT-Password has incorrect length");
                        snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: Configured NT-Password has incorrect length");
                        goto make_msg;
                }
 
-               snprintf(buff2, sizeof(buff2), "%%{mschap:NT-Hash %s}",
-                       request->password->vp_strvalue);
+
+               strlcpy(buff2, "%{mschap:NT-Hash %{User-Password}}", sizeof(buff2));
                if (!radius_xlat(digest, sizeof(digest),buff2,request,NULL)){
-                       DEBUG("rlm_pap: mschap xlat failed");
+                       RDEBUG("mschap xlat failed");
                        snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: mschap xlat failed");
                        goto make_msg;
                }
@@ -726,18 +754,17 @@ static int pap_authenticate(void *instance, REQUEST *request)
 
        case PW_LM_PASSWORD:
        do_lm:
-               DEBUG("rlm_pap: Using LM encryption.");
+               RDEBUG("Using LM encryption.");
 
-               normify(vp, 16);
+               normify(request, vp, 16);
                if (vp->length != 16) {
-                       DEBUG("rlm_pap: Configured LM-Password has incorrect length");
+                       RDEBUG("Configured LM-Password has incorrect length");
                        snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: Configured LM-Password has incorrect length");
                        goto make_msg;
                }
-               snprintf(buff2, sizeof(buff2), "%%{mschap:LM-Hash %s}",
-                       request->password->vp_strvalue);
+               strlcpy(buff2, "%{mschap:LM-Hash %{User-Password}}", sizeof(buff2));
                if (!radius_xlat(digest,sizeof(digest),buff2,request,NULL)){
-                       DEBUG("rlm_pap: mschap xlat failed");
+                       RDEBUG("mschap xlat failed");
                        snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: mschap xlat failed");
                        goto make_msg;
                }
@@ -745,7 +772,7 @@ static int pap_authenticate(void *instance, REQUEST *request)
                    (memcmp(digest, vp->vp_octets, vp->length) != 0)) {
                        snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: LM password check failed");
                make_msg:
-                       DEBUG("rlm_pap: Passwords don't match");
+                       RDEBUG("Passwords don't match");
                        module_fmsg_vp = pairmake("Module-Failure-Message",
                                                  module_fmsg, T_OP_EQ);
                        pairadd(&request->packet->vps, module_fmsg_vp);
@@ -756,10 +783,10 @@ static int pap_authenticate(void *instance, REQUEST *request)
 
        case PAP_ENC_NS_MTA_MD5:
        do_ns_mta_md5:
-               DEBUG("rlm_pap: Using NT-MTA-MD5 password");
+               RDEBUG("Using NT-MTA-MD5 password");
 
                if (vp->length != 64) {
-                       DEBUG("rlm_pap: Configured NS-MTA-MD5-Password has incorrect length");
+                       RDEBUG("Configured NS-MTA-MD5-Password has incorrect length");
                        snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: Configured NS-MTA-MD5-Password has incorrect length");
                        goto make_msg;
                }
@@ -768,7 +795,7 @@ static int pap_authenticate(void *instance, REQUEST *request)
                 *      Sanity check the value of NS-MTA-MD5-Password
                 */
                if (fr_hex2bin(vp->vp_strvalue, buff, 32) != 16) {
-                       DEBUG("rlm_pap: Configured NS-MTA-MD5-Password has invalid value");
+                       RDEBUG("Configured NS-MTA-MD5-Password has invalid value");
                        snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: Configured NS-MTA-MD5-Password has invalid value");
                        goto make_msg;
                }
@@ -779,7 +806,7 @@ static int pap_authenticate(void *instance, REQUEST *request)
                 *      This really: sizeof(buff) - 2 - 2*32 - strlen(passwd)
                 */
                if (strlen(request->password->vp_strvalue) >= (sizeof(buff2) - 2 - 2 * 32)) {
-                       DEBUG("rlm_pap: Configured password is too long");
+                       RDEBUG("Configured password is too long");
                        snprintf(module_fmsg,sizeof(module_fmsg),"rlm_pap: password is too long");
                        goto make_msg;
                }
@@ -814,7 +841,7 @@ static int pap_authenticate(void *instance, REQUEST *request)
                break;
        }
 
-       DEBUG("rlm_pap: No password configured for the user.  Cannot do authentication");
+       RDEBUG("No password configured for the user.  Cannot do authentication");
        return RLM_MODULE_FAIL;
 }