📄 radius.c
字号:
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 'octects'. If the type in the dictionary * is different, then the dictionary type will * over-ride this one. */ create_pair: pair = rad_attr2vp(packet, original, secret, attribute, attrlen, ptr); if (!pair) { pairfree(&packet->vps); librad_log("out of memory"); return -1; } debug_pair(pair); *tail = pair; tail = &pair->next; ptr += attrlen; packet_length -= attrlen; } /* * Merge information from the outside world into our * random pool. */ lrad_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, int *pwlen, const char *secret, const char *vector){ uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 1]; char digest[AUTH_VECTOR_LEN]; int i, n, secretlen; int len; /* * Pad password to multiple of AUTH_PASS_LEN bytes. */ len = *pwlen; if (len > 128) len = 128; *pwlen = len; if (len % AUTH_PASS_LEN != 0) { n = AUTH_PASS_LEN - (len % AUTH_PASS_LEN); for (i = len; n > 0; n--, i++) passwd[i] = 0; len = *pwlen = i; } else if (len == 0) { memset(passwd, 0, AUTH_PASS_LEN); *pwlen = len = AUTH_PASS_LEN; } /* * Use the secret to setup the decryption digest */ secretlen = strlen(secret); memcpy(buffer, secret, secretlen); memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN); librad_md5_calc((u_char *)digest, buffer, secretlen + AUTH_VECTOR_LEN); /* * Now we can encode the password *in place* */ for (i = 0; i < AUTH_PASS_LEN; i++) passwd[i] ^= digest[i]; if (len <= AUTH_PASS_LEN) return 0; /* * Length > AUTH_PASS_LEN, so we need to use the extended * algorithm. */ for (n = 0; n < 128 && n <= (len - AUTH_PASS_LEN); n += AUTH_PASS_LEN) { memcpy(buffer + secretlen, passwd + n, AUTH_PASS_LEN); librad_md5_calc((u_char *)digest, buffer, secretlen + AUTH_PASS_LEN); for (i = 0; i < AUTH_PASS_LEN; i++) passwd[i + n + AUTH_PASS_LEN] ^= digest[i]; } return 0;}/* * Decode password. */int rad_pwdecode(char *passwd, int pwlen, const char *secret, const char *vector){ uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 1]; char digest[AUTH_VECTOR_LEN]; char r[AUTH_VECTOR_LEN]; char *s; int i, n, secretlen; int rlen; /* * Use the secret to setup the decryption digest */ secretlen = strlen(secret); memcpy(buffer, secret, secretlen); memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN); librad_md5_calc((u_char *)digest, buffer, secretlen + AUTH_VECTOR_LEN); /* * Now we can decode the password *in place* */ memcpy(r, passwd, AUTH_PASS_LEN); for (i = 0; i < AUTH_PASS_LEN && i < pwlen; i++) passwd[i] ^= digest[i]; if (pwlen <= AUTH_PASS_LEN) { passwd[pwlen+1] = 0; return pwlen; } /* * Length > AUTH_PASS_LEN, so we need to use the extended * algorithm. */ rlen = ((pwlen - 1) / AUTH_PASS_LEN) * AUTH_PASS_LEN; for (n = rlen; n > 0; n -= AUTH_PASS_LEN ) { s = (n == AUTH_PASS_LEN) ? r : (passwd + n - AUTH_PASS_LEN); memcpy(buffer + secretlen, s, AUTH_PASS_LEN); librad_md5_calc((u_char *)digest, buffer, secretlen + AUTH_PASS_LEN); for (i = 0; i < AUTH_PASS_LEN && (i + n) < pwlen; i++) passwd[i + n] ^= digest[i]; } passwd[pwlen] = 0; return pwlen;}/* * 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, int *pwlen, const char *secret, const char *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) | (lrad_rand() & 0x07)); salt[1] = lrad_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); librad_md5_calc(digest, buffer, secretlen + AUTH_VECTOR_LEN + 2); } else { memcpy(buffer + secretlen, passwd + n2 - AUTH_PASS_LEN, AUTH_PASS_LEN); librad_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, int *pwlen, const char *secret, const char *vector){ uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 3]; uint8_t digest[AUTH_VECTOR_LEN]; uint8_t decrypted[MAX_STRING_LEN + 1]; int secretlen; unsigned i, n, len; 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); /* * Set up the initial key: * * b(1) = MD5(secret + vector + salt) */ memcpy(buffer, secret, secretlen); memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN); memcpy(buffer + secretlen + AUTH_VECTOR_LEN, passwd, 2); librad_md5_calc(digest, buffer, secretlen + AUTH_VECTOR_LEN + 2); /* * A quick check: decrypt the first octet of the password, * which is the 'data_len' field. Ensure it's sane. * * 'n' doesn't include the 'data_len' octet * 'len' does. */ n = passwd[2] ^ digest[0]; if (n >= len) { librad_log("tunnel password is too long for the attribute"); return -1; } /* * Loop over the data, decrypting it, and generating * the key for the next round of decryption. */ for (n = 0; n < len; n += AUTH_PASS_LEN) { for (i = 0; i < AUTH_PASS_LEN; i++) { decrypted[n + i] = passwd[n + i + 2] ^ digest[i]; /* * Encrypted password may not be aligned * on 16 octets, so we catch that here... */ if ((n + i) == len) break; } /* * Update the digest, based on * * b(n) = MD5(secret + cleartext(n-1) * * but only if there's more data... */ memcpy(buffer + secretlen, passwd + n + 2, AUTH_PASS_LEN); librad_md5_calc(digest, buffer, secretlen + AUTH_PASS_LEN); } /* * We've already validated the length of the decrypted * password. Copy it back to the caller. */ memcpy(passwd, decrypted + 1, decrypted[0]); passwd[decrypted[0]] = 0; *pwlen = decrypted[0]; return decrypted[0];}/* * Encode a CHAP password * * FIXME: might not work with Ascend because * we use vp->length, and Ascend gear likes * to send an extra '\0' in the string! */int rad_chap_encode(RADIUS_PACKET *packet, char *output, int id, VALUE_PAIR *password){ int i; char *ptr; char string[MAX_STRING_LEN * 2 + 1]; VALUE_PAIR *challenge; /* * Sanity check the input parameters */ if ((packet == NULL) || (password == NULL)) { return -1; } /* * Note that the password VP can be EITHER * a User-Password attribute (from a check-item list), * or a CHAP-Password attribute (the client asking * the library to encode it). */ i = 0; ptr = string; *ptr++ = id; i++; memcpy(ptr, password->strvalue, password->length); ptr += password->length; i += password->length; /* * Use Chap-Challenge pair if present, * Request-Authenticator otherwise. */ challenge = pairfind(packet->vps, PW_CHAP_CHALLENGE); if (challenge) { memcpy(ptr, challenge->strvalue, challenge->length); i += challenge->length; } else { memcpy(ptr, packet->vector, AUTH_VECTOR_LEN); i += AUTH_VECTOR_LEN; } *output = id; librad_md5_calc((u_char *)output + 1, (u_char *)string, i); return 0;}/* * Seed the random number generator. * * May be called any number of times. */void lrad_rand_seed(const void *data, size_t size){ uint32_t hash; /* * Ensure that the pool is initialized. */ if (lrad_rand_index < 0) { int fd; memset(&lrad_rand_pool, 0, sizeof(lrad_rand_pool)); fd = open("/dev/urandom", O_RDONLY); if (fd >= 0) { size_t total; ssize_t this; total = this = 0; while (total < sizeof(lrad_rand_pool.randrsl)) { this = read(fd, lrad_rand_pool.randrsl, sizeof(lrad_rand_pool.randrsl) - total); if ((this < 0) && (errno != EINTR)) break; if (this > 0) total += this; } close(fd); } else { lrad_rand_pool.randrsl[0] = fd; lrad_rand_pool.randrsl[1] = time(NULL); lrad_rand_pool.randrsl[2] = errno; } lrad_randinit(&lrad_rand_pool, 1); lrad_rand_index = 0; } if (!data) return; /* * Hash the user data */ hash = lrad_hash(data, size); lrad_rand_pool.randrsl[lrad_rand_index & 0xff] ^= hash; lrad_rand_index++; lrad_rand_index &= 0xff; /* * Churn the pool every so often after seeding it. */ if (((int) (hash & 0xff)) == lrad_rand_index) { lrad_isaac(&lrad_rand_pool); }}/* * Return a 32-bit random number. */uint32_t lrad_rand(void){ uint32_t num; /* * Ensure that the pool is initialized. */ if (lrad_rand_index < 0) { lrad_rand_seed(NULL, 0); } /* * We don't return data directly from the pool. * Rather, we return a summary of the data. */ num = lrad_rand_pool.randrsl[lrad_rand_index & 0xff]; lrad_rand_index++; lrad_rand_index &= 0xff; /* * Every so often, churn the pool. */ if (((int) (num & 0xff)) == lrad_rand_index) { lrad_isaac(&lrad_rand_pool); } return num;}/* * Allocate a new RADIUS_PACKET */RADIUS_PACKET *rad_alloc(int newvector){ RADIUS_PACKET *rp; if ((rp = malloc(sizeof(RADIUS_PACKET))) == NULL) { librad_log("out of memory"); return NULL; } memset(rp, 0, sizeof(RADIUS_PACKET)); if (newvector) { int i; uint32_t hash, base; /* * Don't expose the actual contents of the random * pool. */ base = lrad_rand(); for (i = 0; i < AUTH_VECTOR_LEN; i += sizeof(uint32_t)) { hash = lrad_rand() ^ base; memcpy(rp->vector + i, &hash, sizeof(hash)); } } lrad_rand(); return rp;}/* * Free a RADIUS_PACKET */void rad_free(RADIUS_PACKET **radius_packet_ptr){ RADIUS_PACKET *radius_packet; if (!radius_packet_ptr) return; radius_packet = *radius_packet_ptr; if (radius_packet->data) free(radius_packet->data); if (radius_packet->vps) pairfree(&radius_packet->vps); free(radius_packet); *radius_packet_ptr = NULL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -