2 * radius.c Functions to send/receive radius packets.
8 static const char rcsid[] = "$Id$";
18 #include "libradius.h"
21 #include <netinet/in.h>
24 #include <sys/socket.h>
27 #include <arpa/inet.h>
39 * The RFC says 4096 octets max, and most packets are less than 256.
40 * However, this number is just larger than the maximum MTU of just
41 * most types of networks, except maybe for gigabit ethernet.
43 #define PACKET_DATA_LEN 1600
45 typedef struct radius_packet_t {
53 static uint8_t random_vector_pool[AUTH_VECTOR_LEN*2];
55 static const char *packet_codes[] = {
61 "Accounting-Response",
73 * Reply to the request. Also attach
74 * reply attribute value pairs and any user message provided.
76 int rad_send(RADIUS_PACKET *packet, const char *secret)
79 struct sockaddr saremote;
80 struct sockaddr_in *sa;
82 uint8_t ip_buffer[16];
86 if ((packet->code > 0) && (packet->code < 14)) {
87 what = packet_codes[packet->code];
93 * First time through, allocate room for the packet
98 uint8_t *ptr, *length_ptr;
101 int vendorcode, vendorpec;
102 u_short total_length, tmp;
105 hdr = (radius_packet_t *) malloc(PACKET_DATA_LEN);
107 librad_log("Out of memory");
110 packet->data = (uint8_t *) hdr;
113 * Build standard header
115 hdr->code = packet->code;
116 hdr->id = packet->id;
117 if (packet->code == PW_ACCOUNTING_REQUEST)
118 memset(hdr->vector, 0, AUTH_VECTOR_LEN);
120 memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN);
122 DEBUG("Sending %s of id %d to %s:%d\n",
124 ip_ntoa((char *)ip_buffer, packet->dst_ipaddr),
127 total_length = AUTH_HDR_LEN;
130 * Load up the configuration values for the user
133 while (reply != NULL) {
135 * This could be a vendor-specific attribute.
138 if ((vendorcode = VENDOR(reply->attribute)) > 0 &&
139 (vendorpec = dict_vendorpec(vendorcode)) > 0) {
140 *ptr++ = PW_VENDOR_SPECIFIC;
143 lvalue = htonl(vendorpec);
144 memcpy(ptr, &lvalue, 4);
147 } else if (reply->attribute > 0xff) {
149 * Ignore attributes > 0xff
154 vp_print(stdout, reply);
163 if (vendorpec == VENDORPEC_USR) {
164 lvalue = htonl(reply->attribute & 0xFFFF);
165 memcpy(ptr, &lvalue, 4);
171 *ptr++ = (reply->attribute & 0xFF);
173 switch(reply->type) {
177 * If it's a password, encode it.
180 if (reply->attribute == PW_PASSWORD) {
181 rad_pwencode((char *)reply->strvalue,
183 secret, (char *)packet->vector);
186 * If there's a CHAP password, assume it's
187 * currently in clear text, and encode it
190 * The ID is taken from pseudo-random
193 } else if (reply->attribute == PW_CHAP_PASSWORD) {
194 rad_chap_encode(packet, (char *)reply->strvalue,
196 reply->length = 1 + CHAP_VALUE_LENGTH;
200 #ifndef ASCEND_BINARY
201 case PW_TYPE_ABINARY:
206 if (len >= MAX_STRING_LEN) {
207 len = MAX_STRING_LEN - 1;
210 if (vendorpec != VENDORPEC_USR)
213 if (length_ptr) *length_ptr += len + 2;
214 memcpy(ptr, reply->strvalue,len);
216 total_length += len + 2;
219 case PW_TYPE_INTEGER:
222 if (vendorpec != VENDORPEC_USR)
224 *ptr++ = sizeof(uint32_t) + 2;
225 if (length_ptr) *length_ptr += sizeof(uint32_t)+ 2;
226 if (reply->type != PW_TYPE_IPADDR)
227 lvalue = htonl(reply->lvalue);
229 lvalue = reply->lvalue;
230 memcpy(ptr, &lvalue, sizeof(uint32_t));
231 ptr += sizeof(uint32_t);
232 total_length += sizeof(uint32_t) + 2;
235 case PW_TYPE_ABINARY:
237 if (len >= MAX_STRING_LEN) {
238 len = MAX_STRING_LEN - 1;
241 if (vendorpec != VENDORPEC_USR)
244 if (length_ptr) *length_ptr += len + 2;
245 memcpy(ptr, reply->strvalue,len);
247 total_length += len + 2;
256 * Print out ONLY the attributes which we're
257 * sending over the wire. Also, pick up any hacked
258 * password attributes.
264 tmp = htons(total_length);
265 memcpy(hdr->length, &tmp, sizeof(u_short));
266 packet->data_len = total_length;
269 * If this is not an authentication request, we
270 * need to calculate the md5 hash over the entire packet
271 * and put it in the vector.
273 if (packet->code != PW_AUTHENTICATION_REQUEST) {
274 secretlen = strlen(secret);
275 memcpy((char *)hdr + total_length, secret, secretlen);
276 librad_md5_calc(digest, (unsigned char *)hdr,
277 total_length + secretlen);
278 memcpy(hdr->vector, digest, AUTH_VECTOR_LEN);
279 memset((char *)hdr + total_length, 0, secretlen);
283 * If packet->data points to data, then we print out
284 * the VP list again only for debugging.
286 } else if (librad_debug) {
287 DEBUG("Sending %s of id %d to %s\n", what, packet->id,
288 ip_ntoa((char *)ip_buffer, packet->dst_ipaddr));
290 /* FIXME: ignore attributes > 0xff */
297 * And send it on it's way.
299 sa = (struct sockaddr_in *) &saremote;
300 memset ((char *) sa, '\0', sizeof (saremote));
301 sa->sin_family = AF_INET;
302 sa->sin_addr.s_addr = packet->dst_ipaddr;
303 sa->sin_port = htons(packet->dst_port);
305 return sendto(packet->sockfd, packet->data, (int)packet->data_len, 0,
306 &saremote, sizeof(struct sockaddr_in));
311 * Validates the requesting client NAS. Calculates the
312 * signature based on the clients private key.
314 int calc_acctdigest(RADIUS_PACKET *packet, const char *secret, char *recvbuf, int len)
317 u_char digest[AUTH_VECTOR_LEN];
320 * Older clients have the authentication vector set to
321 * all zeros. Return `1' in that case.
323 memset(digest, 0, sizeof(digest));
324 if (memcmp(packet->vector, digest, AUTH_VECTOR_LEN) == 0) {
325 packet->verified = 1;
330 * Zero out the auth_vector in the received packet.
331 * Then append the shared secret to the received packet,
332 * and calculate the MD5 sum. This must be the same
333 * as the original MD5 sum (packet->vector).
335 secretlen = strlen(secret);
336 memset(recvbuf + 4, 0, AUTH_VECTOR_LEN);
337 memcpy(recvbuf + len, secret, secretlen);
338 librad_md5_calc(digest, (u_char *)recvbuf, len + secretlen);
341 * Return 0 if OK, 2 if not OK.
344 memcmp(digest, packet->vector, AUTH_VECTOR_LEN) ? 2 : 0;
346 return packet->verified;
350 * Validates the requesting client NAS. Calculates the
351 * signature based on the clients private key.
353 static int calc_replydigest(RADIUS_PACKET *packet, RADIUS_PACKET *original, const char *secret, char *recvbuf, int len)
356 uint8_t calc_digest[AUTH_VECTOR_LEN];
358 memcpy(recvbuf + 4, original->vector, sizeof(original->vector));
359 secretlen = strlen(secret);
360 memcpy(recvbuf + len, secret, secretlen);
361 librad_md5_calc(calc_digest, (u_char *)recvbuf, len + secretlen);
364 * Return 0 if OK, 2 if not OK.
367 memcmp(packet->vector, calc_digest, sizeof(packet->vector)) ? 2 : 0;
368 return packet->verified;
372 * Receive UDP client requests, and fill in
373 * the basics of a RADIUS_PACKET structure.
375 RADIUS_PACKET *rad_recv(int fd)
377 RADIUS_PACKET *packet;
378 struct sockaddr_in saremote;
384 radius_packet_t *hdr;
385 char host_ipaddr[16];
388 * Allocate the new request data structure
390 if ((packet = malloc(sizeof(RADIUS_PACKET))) == NULL) {
391 librad_log("out of memory");
395 memset(packet, 0, sizeof(RADIUS_PACKET));
396 if ((packet->data = malloc(PACKET_DATA_LEN)) == NULL) {
398 librad_log("out of memory");
404 * Receive the packet.
406 salen = sizeof(saremote);
407 memset(&saremote, 0, sizeof(saremote));
408 packet->data_len = recvfrom(fd, packet->data, PACKET_DATA_LEN,
409 0, (struct sockaddr *)&saremote, &salen);
412 * Fill IP header fields
415 packet->src_ipaddr = saremote.sin_addr.s_addr;
416 packet->src_port = ntohs(saremote.sin_port);
419 * Explicitely set the VP list to empty.
424 * Check for socket errors.
426 if (packet->data_len < 0) {
427 librad_log("Error receiving packet from host %s: %s",
428 ip_ntoa(host_ipaddr, packet->src_ipaddr),
436 * Check for packets smaller than the packet header.
438 if (packet->data_len < AUTH_HDR_LEN) {
439 librad_log("Malformed RADIUS packet from host %s: too short",
440 ip_ntoa(host_ipaddr, packet->src_ipaddr));
447 * Check for packets with mismatched size.
448 * i.e. We've received 128 bytes, and the packet header
449 * says it's 256 bytes long.
451 hdr = (radius_packet_t *)packet->data;
452 memcpy(&len, hdr->length, sizeof(u_short));
453 totallen = ntohs(len);
454 if (packet->data_len != totallen) {
455 librad_log("Malformed RADIUS packet from host %s: received %d octets, packet size says %d",
456 ip_ntoa(host_ipaddr, packet->src_ipaddr),
457 packet->data_len, totallen);
464 * Walk through the packet's attributes, ensuring that
465 * they add up EXACTLY to the size of the packet.
467 * If they don't, then the attributes either under-fill
468 * or over-fill the packet. Any parsing of the packet
469 * is impossible, and will result in unknown side effects.
471 * This would ONLY happen with buggy RADIUS implementations,
472 * or with an intentional attack. Either way, we do NOT want
473 * to be vulnerable to this problem.
476 count = totallen - AUTH_HDR_LEN;
479 * Attribute number zero is NOT defined.
482 librad_log("Malformed RADIUS packet from host %s: Invalid attribute 0",
483 ip_ntoa(host_ipaddr, packet->src_ipaddr));
490 * Attributes are at LEAST as long as the ID & length
491 * fields. Anything shorter is an invalid attribute.
494 librad_log("Malformed RADIUS packet from host %s: attribute %d too short",
495 ip_ntoa(host_ipaddr, packet->src_ipaddr),
501 count -= attr[1]; /* grab the attribute length */
506 * If the attributes add up to a packet, it's allowed.
508 * If not, we complain, and throw the packet away.
511 librad_log("Malformed RADIUS packet from host %s: packet attributes do NOT exactly fill the packet",
512 ip_ntoa(host_ipaddr, packet->src_ipaddr));
519 if ((hdr->code > 0) && (hdr->code < 14)) {
520 printf("rad_recv: %s packet from host %s:%d",
521 packet_codes[hdr->code],
522 ip_ntoa(host_ipaddr, packet->src_ipaddr), packet->src_port);
524 printf("rad_recv: Packet from host %s:%d code=%d",
525 ip_ntoa(host_ipaddr, packet->src_ipaddr), packet->src_port,
528 printf(", id=%d, length=%d\n", hdr->id, totallen);
532 * Fill RADIUS header fields
534 packet->code = hdr->code;
535 packet->id = hdr->id;
536 memcpy(packet->vector, hdr->vector, AUTH_VECTOR_LEN);
542 * Calculate/check digest, and decode radius attributes.
544 int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original, const char *secret)
550 VALUE_PAIR *first_pair;
558 radius_packet_t *hdr;
560 hdr = (radius_packet_t *)packet->data;
561 length = packet->data_len;
564 * Calculate and/or verify digest.
566 switch(packet->code) {
567 case PW_AUTHENTICATION_REQUEST:
569 case PW_ACCOUNTING_REQUEST:
570 if (calc_acctdigest(packet, secret,
571 (char *)packet->data, length) > 1) {
573 librad_log("Received accounting packet "
574 "from %s with invalid signature!",
575 ip_ntoa(buffer, packet->src_ipaddr));
580 /* Verify the reply digest */
581 case PW_AUTHENTICATION_ACK:
582 case PW_AUTHENTICATION_REJECT:
583 if (calc_replydigest(packet, original, secret,
584 (char *)packet->data,
587 librad_log("Received authentication reply packet "
588 "from %s with invalid signature!",
589 ip_ntoa(buffer, packet->src_ipaddr));
594 case PW_ACCOUNTING_RESPONSE:
599 * Extract attribute-value pairs
602 length -= AUTH_HDR_LEN;
612 attribute = *ptr++ | (vendorcode << 16);
618 if (attrlen < 2) { /* rad_recv() now handles this check */
626 * This could be a Vendor-Specific attribute.
629 if (vendorlen <= 0 &&
630 attribute == PW_VENDOR_SPECIFIC && attrlen > 6) {
631 memcpy(&lvalue, ptr, 4);
632 vendorpec = ntohl(lvalue);
633 if ((vendorcode = dict_vendorcode(vendorpec))
636 if (vendorpec == VENDORPEC_USR) {
638 memcpy(&lvalue, ptr, 4);
639 /*printf("received USR %04x\n", ntohl(lvalue));*/
640 attribute = (ntohl(lvalue) & 0xFFFF) |
649 vendorlen = attrlen - 4;
650 attribute = *ptr++ | (vendorcode << 16);
658 if ( attrlen >= MAX_STRING_LEN ) {
659 DEBUG("attribute %d too long, %d >= %d\n", attribute,
660 attrlen, MAX_STRING_LEN);
662 /* rad_recv() now handles this check */
663 else if ( attrlen > length ) {
664 DEBUG("attribute %d longer than buffer left, %d > %d\n",
665 attribute, attrlen, length);
669 * FIXME: should we us paircreate() ?
671 if ((pair = malloc(sizeof(VALUE_PAIR))) == NULL) {
672 pairfree(first_pair);
673 librad_log("out of memory");
678 memset(pair, 0, sizeof(VALUE_PAIR));
679 if ((attr = dict_attrbyvalue(attribute)) == NULL) {
680 sprintf(pair->name, "Attr-%d", attribute);
681 pair->type = PW_TYPE_STRING;
683 strcpy(pair->name, attr->name);
684 pair->type = attr->type;
686 pair->attribute = attribute;
687 pair->length = attrlen;
690 switch (pair->type) {
693 case PW_TYPE_ABINARY:
695 /* attrlen always < MAX_STRING_LEN */
696 memcpy(pair->strvalue, ptr, attrlen);
699 case PW_TYPE_INTEGER:
703 * Check for RFC compliance.
704 * If the attribute isn't compliant,
705 * turn it into a string of raw octets.
707 * Also set the lvalue to something
708 * which should never match anything.
711 pair->type = PW_TYPE_OCTETS;
712 memcpy(pair->strvalue, ptr, attrlen);
713 pair->lvalue = 0xbaddbadd;
716 memcpy(&lvalue, ptr, 4);
717 if (attr->type != PW_TYPE_IPADDR)
718 pair->lvalue = ntohl(lvalue);
720 pair->lvalue = lvalue;
724 DEBUG(" %s (Unknown Type %d)\n",
725 attr->name,attr->type);
733 if (first_pair == NULL)
742 if (vendorlen > 0) vendorlen -= (attrlen + 2);
745 packet->vps = first_pair;
748 * Merge information from the outside world into our
749 * random vector pool. The MD5 is expensive, but it's
750 * amortized over *legal* packets from *known* clients,
751 * so the problem isn't too bad.
753 * The MD5 helps to make sure that the random pool uses
754 * information from outside to increase entropy, without
755 * being contaminated by that information.
757 * Both AUTH_VECTOR_LEN and the MD5 output are 16 octets
758 * long, so we copy the user's vector to the end of our
759 * pool, and make the pool out of the hash of the two.
761 * However, doing this for *every* packet can be time
762 * consuming. Instead, we do it (on average) once every
763 * 32 packets, and do less work the rest of the time.
765 if ((random_vector_pool[0] & 0x1f) == 0x00) {
766 memcpy((char *) random_vector_pool + AUTH_VECTOR_LEN,
767 (char *) packet->vector, AUTH_VECTOR_LEN);
768 librad_md5_calc((u_char *)random_vector_pool,
769 (u_char *)random_vector_pool,
770 sizeof(random_vector_pool));
772 } else for (length = 0; length < AUTH_VECTOR_LEN; length++) {
773 random_vector_pool[length] += packet->vector[length];
783 * We assume that the passwd buffer passed is big enough.
784 * RFC2138 says the password is max 128 chars, so the size
785 * of the passwd buffer must be at least 129 characters.
786 * Preferably it's just MAX_STRING_LEN.
788 * int *pwlen is updated to the new length of the encrypted
789 * password - a multiple of 16 bytes.
791 int rad_pwencode(char *passwd, int *pwlen, const char *secret, const char *vector)
793 uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 1];
794 char digest[AUTH_VECTOR_LEN];
799 * Padd password to multiple of 16 bytes.
801 len = strlen(passwd);
802 if (len > 128) len = 128;
806 for (i = len; n > 0; n--, i++)
812 * Use the secret to setup the decryption digest
814 secretlen = strlen(secret);
815 strcpy(buffer, secret);
816 memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN);
817 librad_md5_calc((u_char *)digest, buffer, secretlen + AUTH_VECTOR_LEN);
820 * Now we can encode the password *in place*
822 for (i = 0; i < 16; i++)
823 passwd[i] ^= digest[i];
825 if (len <= 16) return 0;
828 * Length > 16, so we need to use the extended
831 for (n = 0; n < 128 && n <= (len - 16); n += 16) {
832 memcpy(buffer + secretlen, passwd + n, 16);
833 librad_md5_calc((u_char *)digest, buffer, secretlen + 16);
834 for (i = 0; i < 16; i++)
835 passwd[i + n + 16] ^= digest[i];
844 int rad_pwdecode(char *passwd, int pwlen, const char *secret, const char *vector)
846 uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 1];
847 char digest[AUTH_VECTOR_LEN];
848 char r[AUTH_VECTOR_LEN];
854 * Use the secret to setup the decryption digest
856 secretlen = strlen(secret);
857 strcpy(buffer, secret);
858 memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN);
859 librad_md5_calc((u_char *)digest, buffer, secretlen + AUTH_VECTOR_LEN);
862 * Now we can decode the password *in place*
864 memcpy(r, passwd, 16);
865 for (i = 0; i < 16 && i < pwlen; i++)
866 passwd[i] ^= digest[i];
874 * Length > 16, so we need to use the extended
877 rlen = ((pwlen - 1) / 16) * 16;
879 for (n = rlen; n > 0; n -= 16 ) {
880 s = (n == 16) ? r : (passwd + n - 16);
881 memcpy(buffer + secretlen, s, 16);
882 librad_md5_calc((u_char *)digest, buffer, secretlen + 16);
883 for (i = 0; i < 16 && (i + n) < pwlen; i++)
884 passwd[i + n] ^= digest[i];
892 * Encode a CHAP password
894 * FIXME: might not work with Ascend because
895 * we use vp->length, and Ascend gear likes
896 * to send an extra '\0' in the string!
898 int rad_chap_encode(RADIUS_PACKET *packet, char *output, int id, VALUE_PAIR *password)
902 char string[MAX_STRING_LEN];
903 VALUE_PAIR *challenge;
906 * Sanity check the input parameters
908 if ((packet == NULL) || (password == NULL)) {
913 * Note that the password VP can be EITHER
914 * a Password attribute (from a check-item list),
915 * or a CHAP-Password attribute (the client asking
916 * the library to encode it).
924 memcpy(ptr, password->strvalue, password->length);
925 ptr += password->length;
926 i += password->length;
929 * Use Chap-Challenge pair if present,
930 * Request-Authenticator otherwise.
932 challenge = pairfind(packet->vps, PW_CHAP_CHALLENGE);
934 memcpy(ptr, challenge->strvalue, challenge->length);
935 i += challenge->length;
937 memcpy(ptr, packet->vector, AUTH_VECTOR_LEN);
938 i += AUTH_VECTOR_LEN;
942 librad_md5_calc((u_char *)output + 1, (u_char *)string, i);
948 * Create a random vector of AUTH_VECTOR_LEN bytes.
950 static void random_vector(uint8_t *vector)
953 static int did_srand = 0;
954 static int counter = 0;
956 static int urandom_fd = -1;
959 * Use /dev/urandom if available.
961 if (urandom_fd > -2) {
963 * Open urandom fd if not yet opened.
966 urandom_fd = open("/dev/urandom", O_RDONLY);
967 if (urandom_fd < 0) {
969 * It's not there, don't try
972 DEBUG("Cannot open /dev/urandom, using rand()\n");
976 fcntl(urandom_fd, F_SETFD, 1);
981 if (read(urandom_fd, (char *) vector, AUTH_VECTOR_LEN)
985 * We didn't get 16 bytes - fall
986 * back on rand) and don't try again.
988 DEBUG("Read short packet from /dev/urandom, using rand()\n");
995 srand(time(NULL) + getpid());
998 * Now that we have a bad random seed, let's
999 * make it a little better by MD5'ing it.
1001 for (i = 0; i < (int)sizeof(random_vector_pool); i++) {
1002 random_vector_pool[i] += rand() & 0xff;
1005 librad_md5_calc((u_char *) random_vector_pool,
1006 (u_char *) random_vector_pool,
1007 sizeof(random_vector_pool));
1013 * Modify our random pool, based on the counter,
1014 * and put the resulting information through MD5,
1015 * so it's all mashed together.
1018 random_vector_pool[AUTH_VECTOR_LEN] += (counter & 0xff);
1019 librad_md5_calc((u_char *) random_vector_pool,
1020 (u_char *) random_vector_pool,
1021 sizeof(random_vector_pool));
1024 * And do another MD5 hash of the result, to give
1025 * the user a random vector. This ensures that the
1026 * user has a random vector, without giving them
1027 * an exact image of what's in the random pool.
1029 librad_md5_calc((u_char *) vector,
1030 (u_char *) random_vector_pool,
1031 sizeof(random_vector_pool));
1036 * Allocate a new RADIUS_PACKET
1038 RADIUS_PACKET *rad_alloc(int newvector)
1042 if ((rp = malloc(sizeof(RADIUS_PACKET))) == NULL)
1044 memset(rp, 0, sizeof(RADIUS_PACKET));
1046 random_vector(rp->vector);
1052 * Free a RADIUS_PACKET
1054 void rad_free(RADIUS_PACKET *rp)
1056 if (rp->data) free(rp->data);
1057 if (rp->vps) pairfree(rp->vps);