📄 radius.c
字号:
/* * attrlen was checked above. */ memcpy(&lvalue, ptr, 4); myvendor = ntohl(lvalue); /* * Zero isn't allowed. */ if (myvendor == 0) goto create_pair; /* * This is an implementation issue. * We currently pack vendor into the upper * 16 bits of a 32-bit attribute number, * so we can't handle vendor numbers larger * than 16 bits. */ if (myvendor > 65535) goto create_pair; vsa_tlen = vsa_llen = 1; dv = dict_vendorbyvalue(myvendor); if (dv) { vsa_tlen = dv->type; vsa_llen = dv->length; } /* * Sweep through the list of VSA's, * seeing if they exactly fill the * outer Vendor-Specific attribute. * * If not, create a raw Vendor-Specific. */ subptr = ptr + 4; sublen = attrlen - 4; /* * See if we can parse it. */ do { int myattr = 0; /* * Don't have a type, it's bad. */ if (sublen < vsa_tlen) goto create_pair; /* * Ensure that the attribute number * is OK. */ switch (vsa_tlen) { case 1: myattr = subptr[0]; break; case 2: myattr = (subptr[0] << 8) | subptr[1]; break; case 4: if ((subptr[0] != 0) || (subptr[1] != 0)) goto create_pair; myattr = (subptr[2] << 8) | subptr[3]; break; /* * Our dictionary is broken. */ default: goto create_pair; } /* * Not enough room for one more * attribute. Die! */ if (sublen < vsa_tlen + vsa_llen) goto create_pair; switch (vsa_llen) { case 0: attribute = (myvendor << 16) | myattr; ptr += 4 + vsa_tlen; attrlen -= (4 + vsa_tlen); packet_length -= 4 + vsa_tlen; goto create_pair; case 1: if (subptr[vsa_tlen] < (vsa_tlen + vsa_llen)) goto create_pair; if (subptr[vsa_tlen] > sublen) goto create_pair; sublen -= subptr[vsa_tlen]; subptr += subptr[vsa_tlen]; break; case 2: if (subptr[vsa_tlen] != 0) goto create_pair; if (subptr[vsa_tlen + 1] < (vsa_tlen + vsa_llen)) goto create_pair; if (subptr[vsa_tlen + 1] > sublen) goto create_pair; sublen -= subptr[vsa_tlen + 1]; subptr += subptr[vsa_tlen + 1]; break; /* * Our dictionaries are * broken. */ default: goto create_pair; } } while (sublen > 0); vendorcode = myvendor; vendorlen = attrlen - 4; packet_length -= 4; ptr += 4; } /* * attrlen is the length of this attribute. * total_len is the length of the encompassing * attribute. */ switch (vsa_tlen) { case 1: attribute = ptr[0]; break; case 2: attribute = (ptr[0] << 8) | ptr[1]; break; default: /* can't hit this. */ return -1; } attribute |= (vendorcode << 16); ptr += vsa_tlen; switch (vsa_llen) { case 1: attrlen = ptr[0] - (vsa_tlen + vsa_llen); break; case 2: attrlen = ptr[1] - (vsa_tlen + vsa_llen); break; default: /* can't hit this. */ return -1; } ptr += vsa_llen; vendorlen -= vsa_tlen + vsa_llen + attrlen; if (vendorlen == 0) vendorcode = 0; packet_length -= (vsa_tlen + vsa_llen); /* * Create the attribute, setting the default type * to 'octets'. If the type in the dictionary * is different, then the dictionary type will * over-ride this one. * * If the attribute has no data, then discard it. */ create_pair: if (!attrlen) goto next; pair = rad_attr2vp(packet, original, secret, attribute, attrlen, ptr); if (!pair) { pairfree(&packet->vps); librad_log("out of memory"); return -1; } *tail = pair; while (pair) { num_attributes++; debug_pair(pair); tail = &pair->next; pair = pair->next; } /* * VSA's may not have been counted properly in * rad_packet_ok() above, as it is hard to count * then without using the dictionary. We * therefore enforce the limits here, too. */ if ((librad_max_attributes > 0) && (num_attributes > librad_max_attributes)) { char host_ipaddr[128]; pairfree(&packet->vps); librad_log("WARNING: Possible DoS attack from host %s: Too many attributes in request (received %d, max %d are allowed).", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, host_ipaddr, sizeof(host_ipaddr)), num_attributes, librad_max_attributes); return -1; } next: ptr += attrlen; packet_length -= attrlen; } /* * Merge information from the outside world into our * random pool. */ fr_rand_seed(packet->data, AUTH_HDR_LEN); return 0;}/* * Encode password. * * We assume that the passwd buffer passed is big enough. * RFC2138 says the password is max 128 chars, so the size * of the passwd buffer must be at least 129 characters. * Preferably it's just MAX_STRING_LEN. * * int *pwlen is updated to the new length of the encrypted * password - a multiple of 16 bytes. */int rad_pwencode(char *passwd, size_t *pwlen, const char *secret, const uint8_t *vector){ FR_MD5_CTX context, old; uint8_t digest[AUTH_VECTOR_LEN]; int i, n, secretlen; int len; /* * RFC maximum is 128 bytes. * * If length is zero, pad it out with zeros. * * If the length isn't aligned to 16 bytes, * zero out the extra data. */ len = *pwlen; if (len > 128) len = 128; if (len == 0) { memset(passwd, 0, AUTH_PASS_LEN); len = AUTH_PASS_LEN; } else if ((len % AUTH_PASS_LEN) != 0) { memset(&passwd[len], 0, AUTH_PASS_LEN - (len % AUTH_PASS_LEN)); len += AUTH_PASS_LEN - (len % AUTH_PASS_LEN); } *pwlen = len; /* * Use the secret to setup the decryption digest */ secretlen = strlen(secret); fr_MD5Init(&context); fr_MD5Update(&context, (const uint8_t *) secret, secretlen); old = context; /* save intermediate work */ /* * Encrypt it in place. Don't bother checking * len, as we've ensured above that it's OK. */ for (n = 0; n < len; n += AUTH_PASS_LEN) { if (n == 0) { fr_MD5Update(&context, vector, AUTH_PASS_LEN); fr_MD5Final(digest, &context); } else { context = old; fr_MD5Update(&context, (uint8_t *) passwd + n - AUTH_PASS_LEN, AUTH_PASS_LEN); fr_MD5Final(digest, &context); } for (i = 0; i < AUTH_PASS_LEN; i++) { passwd[i + n] ^= digest[i]; } } return 0;}/* * Decode password. */int rad_pwdecode(char *passwd, size_t pwlen, const char *secret, const uint8_t *vector){ FR_MD5_CTX context, old; uint8_t digest[AUTH_VECTOR_LEN]; int i; size_t n, secretlen; /* * The RFC's say that the maximum is 128. * The buffer we're putting it into above is 254, so * we don't need to do any length checking. */ if (pwlen > 128) pwlen = 128; /* * Catch idiots. */ if (pwlen == 0) goto done; /* * Use the secret to setup the decryption digest */ secretlen = strlen(secret); fr_MD5Init(&context); fr_MD5Update(&context, (const uint8_t *) secret, secretlen); old = context; /* save intermediate work */ /* * The inverse of the code above. */ for (n = 0; n < pwlen; n += AUTH_PASS_LEN) { if (n == 0) { fr_MD5Update(&context, vector, AUTH_VECTOR_LEN); fr_MD5Final(digest, &context); context = old; if (pwlen > AUTH_PASS_LEN) { fr_MD5Update(&context, (uint8_t *) passwd, AUTH_PASS_LEN); } } else { fr_MD5Final(digest, &context); context = old; if (pwlen > (n + AUTH_PASS_LEN)) { fr_MD5Update(&context, (uint8_t *) passwd + n, AUTH_PASS_LEN); } } for (i = 0; i < AUTH_PASS_LEN; i++) { passwd[i + n] ^= digest[i]; } } done: passwd[pwlen] = '\0'; return strlen(passwd);}/* * Encode Tunnel-Password attributes when sending them out on the wire. * * int *pwlen is updated to the new length of the encrypted * password - a multiple of 16 bytes. * * This is per RFC-2868 which adds a two char SALT to the initial intermediate * value MD5 hash. */int rad_tunnel_pwencode(char *passwd, size_t *pwlen, const char *secret, const uint8_t *vector){ uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 3]; unsigned char digest[AUTH_VECTOR_LEN]; char* salt; int i, n, secretlen; unsigned len, n2; len = *pwlen; if (len > 127) len = 127; /* * Shift the password 3 positions right to place a salt and original * length, tag will be added automatically on packet send */ for (n=len ; n>=0 ; n--) passwd[n+3] = passwd[n]; salt = passwd; passwd += 2; /* * save original password length as first password character; */ *passwd = len; len += 1; /* * Generate salt. The RFC's say: * * The high bit of salt[0] must be set, each salt in a * packet should be unique, and they should be random * * So, we set the high bit, add in a counter, and then * add in some CSPRNG data. should be OK.. */ salt[0] = (0x80 | ( ((salt_offset++) & 0x0f) << 3) | (fr_rand() & 0x07)); salt[1] = fr_rand(); /* * Padd password to multiple of AUTH_PASS_LEN bytes. */ n = len % AUTH_PASS_LEN; if (n) { n = AUTH_PASS_LEN - n; for (; n > 0; n--, len++) passwd[len] = 0; } /* set new password length */ *pwlen = len + 2; /* * Use the secret to setup the decryption digest */ secretlen = strlen(secret); memcpy(buffer, secret, secretlen); for (n2 = 0; n2 < len; n2+=AUTH_PASS_LEN) { if (!n2) { memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN); memcpy(buffer + secretlen + AUTH_VECTOR_LEN, salt, 2); fr_md5_calc(digest, buffer, secretlen + AUTH_VECTOR_LEN + 2); } else { memcpy(buffer + secretlen, passwd + n2 - AUTH_PASS_LEN, AUTH_PASS_LEN); fr_md5_calc(digest, buffer, secretlen + AUTH_PASS_LEN); } for (i = 0; i < AUTH_PASS_LEN; i++) { passwd[i + n2] ^= digest[i]; } } passwd[n2] = 0; return 0;}/* * Decode Tunnel-Password encrypted attributes. * * Defined in RFC-2868, this uses a two char SALT along with the * initial intermediate value, to differentiate it from the * above. */int rad_tunnel_pwdecode(uint8_t *passwd, size_t *pwlen, const char *secret, const uint8_t *vector){ FR_MD5_CTX context, old; uint8_t digest[AUTH_VECTOR_LEN]; int secretlen; unsigned i, n, len, reallen; len = *pwlen; /* * We need at least a salt. */ if (len < 2) { librad_log("tunnel password is too short"); return -1; } /* * There's a salt, but no password. Or, there's a salt * and a 'data_len' octet. It's wrong, but at least we * can figure out what it means: the password is empty. * * Note that this means we ignore the 'data_len' field, * if the attribute length tells us that there's no * more data. So the 'data_len' field may be wrong, * but that's ok... */ if (len <= 3) { passwd[0] = 0; *pwlen = 0; return 0; } len -= 2; /* discount the salt */ /* * Use the secret to setup the decryption digest */ secretlen = strlen(secret); fr_MD5Init(&context); fr_MD5Update(&context, (const uint8_t *) secret, secretlen); old = context; /* save intermediate work */ /* * Set up the initial key: * * b(1) = MD5(secret + vector + salt) */ fr_MD5Update(&context, vector, AUTH_VECTOR_LEN); fr_MD5Update(&context, passwd, 2); reallen = 0; for (n = 0; n < len; n += AUTH_PASS_LEN) { int base = 0; if (n == 0) { fr_MD5Final(digest, &context); context = old; /* * A quick check: decrypt the first octet * of the password, which is the * 'data_len' field. Ensure it's sane. */ reallen = passwd[2] ^ digest[0]; if (reallen >= len) { librad_log("tunnel password is too long for the attribute"); return -1; } fr_MD5Update(&context, passwd + 2, AUTH_PASS_LEN); base = 1; } else { fr_MD5Final(digest, &context); context = old; fr_MD5Update(&context, passwd + n + 2, AUTH_PASS_LEN); } for (i = base; i < AUTH_PASS_LEN; i++) { passwd[n + i - 1] = passwd[n + i + 2] ^ digest[i]; } } /* * See make_tunnel_password, above. */ if (reallen > 239) reallen = 239; *pwlen = reallen; passwd[reallen] = 0; return reallen;}/* * Encode a CHAP password * * FIXME: might not work with Ascend because * we use vp->length, and Ascend gear likes
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -