2 * radius.c Functions to send/receive radius packets.
8 static const char rcsid[] = "$Id$";
23 #include "libradius.h"
26 #include <netinet/in.h>
29 #include <sys/socket.h>
32 #include <arpa/inet.h>
44 * The RFC says 4096 octets max, and most packets are less than 256.
45 * However, this number is just larger than the maximum MTU of just
46 * most types of networks, except maybe for gigabit ethernet.
48 #define PACKET_DATA_LEN 1600
51 * The maximum number of attributes which we allow in an incoming
52 * request. If there are more attributes than this, the request
55 * This helps to minimize the potential for a DoS, when an
56 * attacker spoofs Access-Request packets, which don't have a
57 * Message-Authenticator attribute. This means that the packet
58 * is unsigned, and the attacker can use resources on the server,
59 * even if the end request is rejected.
61 int librad_max_attributes = 0;
63 typedef struct radius_packet_t {
71 static uint8_t random_vector_pool[AUTH_VECTOR_LEN*2];
73 static const char *packet_codes[] = {
79 "Accounting-Response",
93 static void make_secret(unsigned char *digest, uint8_t *vector,
94 const char *secret, char *value);
97 * Reply to the request. Also attach
98 * reply attribute value pairs and any user message provided.
100 int rad_send(RADIUS_PACKET *packet, const RADIUS_PACKET *original, const char *secret)
103 struct sockaddr_in saremote;
104 struct sockaddr_in *sa;
106 uint8_t ip_buffer[16];
108 if ((packet->code > 0) && (packet->code < 14)) {
109 what = packet_codes[packet->code];
115 * First time through, allocate room for the packet
118 radius_packet_t *hdr;
120 uint8_t *ptr, *length_ptr, *vsa_length_ptr;
123 int vendorcode, vendorpec;
124 u_short total_length;
126 int msg_auth_offset = 0;
130 * Use memory on the stack, until we know how
131 * large the packet will be.
133 hdr = (radius_packet_t *) data;
136 * Build standard header
138 hdr->code = packet->code;
139 hdr->id = packet->id;
140 if (packet->code == PW_ACCOUNTING_REQUEST) {
141 memset(hdr->vector, 0, AUTH_VECTOR_LEN);
143 memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN);
146 DEBUG("Sending %s of id %d to %s:%d\n",
148 ip_ntoa((char *)ip_buffer, packet->dst_ipaddr),
151 total_length = AUTH_HDR_LEN;
154 * Load up the configuration values for the user
159 vsa_length_ptr = NULL;
161 for (reply = packet->vps; reply; reply = reply->next) {
163 * Ignore non-wire attributes
165 if ((VENDOR(reply->attribute) == 0) &&
166 ((reply->attribute & 0xFFFF) > 0xff)) {
171 * Do stuff for Message-Authenticator
173 if (reply->attribute == PW_MESSAGE_AUTHENTICATOR) {
177 reply->length = AUTH_VECTOR_LEN;
178 memset(reply->strvalue, 0, AUTH_VECTOR_LEN);
179 msg_auth_offset = total_length;
183 * We have a different vendor. Re-set
186 if (vendorcode != VENDOR(reply->attribute)) {
189 vsa_length_ptr = NULL;
193 * If the Vendor-Specific attribute is getting
194 * full, then create a new VSA attribute
196 * FIXME: Multiple VSA's per Vendor-Specific
197 * SHOULD be configurable. When that's done,
198 * the (1), below, can be changed to point to
199 * a configuration variable which is set TRUE
200 * if the NAS cannot understand multiple VSA's
201 * per Vendor-Specific
203 if ((1) || /* ALWAYS create a new Vendor-Specific */
205 (reply->length + *vsa_length_ptr) >= MAX_STRING_LEN)) {
208 vsa_length_ptr = NULL;
212 * Maybe we have the start of a set of
213 * (possibly many) VSA attributes from
214 * one vendor. Set a global VSA wrapper
216 if ((vendorcode == 0) &&
217 ((vendorcode = VENDOR(reply->attribute)) != 0)) {
218 vendorpec = dict_vendorpec(vendorcode);
221 * This is a potentially bad error...
222 * we can't find the vendor ID!
224 if (vendorpec == 0) {
225 /* FIXME: log an error */
230 * Build a VSA header.
232 *ptr++ = PW_VENDOR_SPECIFIC;
233 vsa_length_ptr = ptr;
235 lvalue = htonl(vendorpec);
236 memcpy(ptr, &lvalue, 4);
241 if (vendorpec == VENDORPEC_USR) {
242 lvalue = htonl(reply->attribute & 0xFFFF);
243 memcpy(ptr, &lvalue, 4);
245 length_ptr = vsa_length_ptr;
252 * Each USR attribute gets it's own
253 * VSA wrapper, so we re-set the
254 * vendor specific information.
258 vsa_length_ptr = NULL;
262 * All other attributes are as
266 *ptr++ = (reply->attribute & 0xFF);
268 if (vsa_length_ptr) *vsa_length_ptr += 2;
273 switch(reply->type) {
276 * Ascend binary attributes are
277 * stored internally in binary form.
279 case PW_TYPE_ABINARY:
283 * Hmm... this is based on names
284 * right now. We really shouldn't do
285 * this. It should be based on the value
286 * of the attribute (VSA or not).
288 if ((strcmp(reply->name, "Ascend-Send-Secret") == 0) ||
289 (strcmp(reply->name, "Ascend-Receive-Secret") == 0)) {
290 make_secret(digest, packet->vector,
291 secret, reply->strvalue);
292 memcpy(reply->strvalue, digest, AUTH_VECTOR_LEN );
293 reply->length = AUTH_VECTOR_LEN;
298 * Ensure we don't go too far.
299 * The 'length' of the attribute
300 * may be 0..255, minus whatever
301 * octets are used in the attribute
305 if (vsa_length_ptr) {
306 allowed -= *vsa_length_ptr;
308 allowed -= *length_ptr;
316 if (vsa_length_ptr) *vsa_length_ptr += len;
317 memcpy(ptr, reply->strvalue,len);
322 case PW_TYPE_INTEGER:
325 if (vsa_length_ptr) *vsa_length_ptr += 4;
326 if (reply->type != PW_TYPE_IPADDR)
327 lvalue = htonl(reply->lvalue);
329 lvalue = reply->lvalue;
330 memcpy(ptr, &lvalue, 4);
340 * Print out ONLY the attributes which
341 * we're sending over the wire. Also,
342 * pick up any hacked password
346 } /* done looping over all attributes */
349 * Fill in the rest of the fields, and copy
350 * the data over from the local stack to
351 * the newly allocated memory.
353 * Yes, all this 'memcpy' is slow, but it means
354 * that we only allocate the minimum amount of
355 * memory for a request.
357 packet->data_len = total_length;
358 packet->data = (uint8_t *) malloc(packet->data_len);
360 librad_log("Out of memory");
363 memcpy(packet->data, data, packet->data_len);
364 hdr = (radius_packet_t *) packet->data;
366 total_length = htons(total_length);
367 memcpy(hdr->length, &total_length, sizeof(u_short));
370 * If this is not an authentication request, we
371 * need to calculate the md5 hash over the entire packet
372 * and put it in the vector.
374 secretlen = strlen(secret);
375 if (packet->code != PW_AUTHENTICATION_REQUEST &&
376 packet->code != PW_STATUS_SERVER) {
379 * Set the Message-Authenticator attribute,
380 * BEFORE setting the reply authentication vector
381 * for CHALLENGE, ACCEPT and REJECT.
383 if (msg_auth_offset) {
384 uint8_t calc_auth_vector[AUTH_VECTOR_LEN];
386 switch (packet->code) {
390 case PW_AUTHENTICATION_ACK:
391 case PW_AUTHENTICATION_REJECT:
392 case PW_ACCESS_CHALLENGE:
394 memcpy(hdr->vector, original->vector, AUTH_VECTOR_LEN);
399 memset(packet->data + msg_auth_offset + 2, 0,
401 lrad_hmac_md5(packet->data, packet->data_len,
402 secret, secretlen, calc_auth_vector);
403 memcpy(packet->data + msg_auth_offset + 2,
404 calc_auth_vector, AUTH_VECTOR_LEN);
405 memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN);
409 MD5Update(&context, packet->data, packet->data_len);
410 MD5Update(&context, secret, strlen(secret));
411 MD5Final(digest, &context);
413 memcpy(hdr->vector, digest, AUTH_VECTOR_LEN);
414 memcpy(packet->vector, digest, AUTH_VECTOR_LEN);
418 * Set the Message-Authenticator attribute,
419 * AFTER setting the authentication vector
420 * only for ACCESS-REQUESTS
422 else if (msg_auth_offset) {
423 uint8_t calc_auth_vector[AUTH_VECTOR_LEN];
425 switch (packet->code) {
429 case PW_AUTHENTICATION_ACK:
430 case PW_AUTHENTICATION_REJECT:
431 case PW_ACCESS_CHALLENGE:
433 memcpy(hdr->vector, original->vector, AUTH_VECTOR_LEN);
438 memset(packet->data + msg_auth_offset + 2,
440 lrad_hmac_md5(packet->data, packet->data_len,
441 secret, secretlen, calc_auth_vector);
442 memcpy(packet->data + msg_auth_offset + 2,
443 calc_auth_vector, AUTH_VECTOR_LEN);
444 memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN);
448 * If packet->data points to data, then we print out
449 * the VP list again only for debugging.
451 } else if (librad_debug) {
452 DEBUG("Sending %s of id %d to %s\n", what, packet->id,
453 ip_ntoa((char *)ip_buffer, packet->dst_ipaddr));
455 for (reply = packet->vps; reply; reply = reply->next) {
456 /* FIXME: ignore attributes > 0xff */
462 * And send it on it's way.
464 sa = (struct sockaddr_in *) &saremote;
465 memset ((char *) sa, '\0', sizeof (saremote));
466 sa->sin_family = AF_INET;
467 sa->sin_addr.s_addr = packet->dst_ipaddr;
468 sa->sin_port = htons(packet->dst_port);
470 return sendto(packet->sockfd, packet->data, (int)packet->data_len, 0,
471 &saremote, sizeof(struct sockaddr_in));
476 * Validates the requesting client NAS. Calculates the
477 * signature based on the clients private key.
479 static int calc_acctdigest(RADIUS_PACKET *packet, const char *secret)
481 u_char digest[AUTH_VECTOR_LEN];
485 * Older clients have the authentication vector set to
486 * all zeros. Return `1' in that case.
488 memset(digest, 0, sizeof(digest));
489 if (memcmp(packet->vector, digest, AUTH_VECTOR_LEN) == 0) {
490 packet->verified = 1;
495 * Zero out the auth_vector in the received packet.
496 * Then append the shared secret to the received packet,
497 * and calculate the MD5 sum. This must be the same
498 * as the original MD5 sum (packet->vector).
500 memset(packet->data + 4, 0, AUTH_VECTOR_LEN);
503 * MD5(packet + secret);
506 MD5Update(&context, packet->data, packet->data_len);
507 MD5Update(&context, secret, strlen(secret));
508 MD5Final(digest, &context);
511 * Return 0 if OK, 2 if not OK.
514 memcmp(digest, packet->vector, AUTH_VECTOR_LEN) ? 2 : 0;
516 return packet->verified;
520 * Validates the requesting client NAS. Calculates the
521 * signature based on the clients private key.
523 static int calc_replydigest(RADIUS_PACKET *packet, RADIUS_PACKET *original, const char *secret)
525 uint8_t calc_digest[AUTH_VECTOR_LEN];
529 * Copy the original vector in place.
531 memcpy(packet->data + 4, original->vector, sizeof(original->vector));
534 * MD5(packet + secret);
537 MD5Update(&context, packet->data, packet->data_len);
538 MD5Update(&context, secret, strlen(secret));
539 MD5Final(calc_digest, &context);
542 * Copy the packet's vector back to the packet.
544 memcpy(packet->data + 4, packet->vector, sizeof(packet->vector));
547 * Return 0 if OK, 2 if not OK.
550 memcmp(packet->vector, calc_digest, sizeof(packet->vector)) ? 2 : 0;
551 return packet->verified;
555 * Receive UDP client requests, and fill in
556 * the basics of a RADIUS_PACKET structure.
558 RADIUS_PACKET *rad_recv(int fd)
560 RADIUS_PACKET *packet;
561 struct sockaddr_in saremote;
567 radius_packet_t *hdr;
568 char host_ipaddr[16];
574 * Allocate the new request data structure
576 if ((packet = malloc(sizeof(RADIUS_PACKET))) == NULL) {
577 librad_log("out of memory");
581 memset(packet, 0, sizeof(RADIUS_PACKET));
584 * Receive the packet.
586 salen = sizeof(saremote);
587 memset(&saremote, 0, sizeof(saremote));
588 packet->data_len = recvfrom(fd, data, sizeof(data),
589 0, (struct sockaddr *)&saremote, &salen);
592 * Fill IP header fields. We need these for the error
593 * messages which may come later.
596 packet->src_ipaddr = saremote.sin_addr.s_addr;
597 packet->src_port = ntohs(saremote.sin_port);
600 * Explicitely set the VP list to empty.
605 * Check for socket errors.
607 if (packet->data_len < 0) {
608 librad_log("Error receiving packet from host %s: %s",
609 ip_ntoa(host_ipaddr, packet->src_ipaddr),
616 * Check for packets smaller than the packet header.
618 if (packet->data_len < AUTH_HDR_LEN) {
619 librad_log("WARNING: Malformed RADIUS packet from host %s: too short",
620 ip_ntoa(host_ipaddr, packet->src_ipaddr));
626 * Check for packets with mismatched size.
627 * i.e. We've received 128 bytes, and the packet header
628 * says it's 256 bytes long.
630 hdr = (radius_packet_t *)data;
631 memcpy(&len, hdr->length, sizeof(u_short));
632 totallen = ntohs(len);
633 if (packet->data_len != totallen) {
634 librad_log("WARNING: Malformed RADIUS packet from host %s: received %d octets, packet size says %d",
635 ip_ntoa(host_ipaddr, packet->src_ipaddr),
636 packet->data_len, totallen);
642 * Walk through the packet's attributes, ensuring that
643 * they add up EXACTLY to the size of the packet.
645 * If they don't, then the attributes either under-fill
646 * or over-fill the packet. Any parsing of the packet
647 * is impossible, and will result in unknown side effects.
649 * This would ONLY happen with buggy RADIUS implementations,
650 * or with an intentional attack. Either way, we do NOT want
651 * to be vulnerable to this problem.
654 count = totallen - AUTH_HDR_LEN;
660 * Attribute number zero is NOT defined.
663 librad_log("WARNING: Malformed RADIUS packet from host %s: Invalid attribute 0",
664 ip_ntoa(host_ipaddr, packet->src_ipaddr));
670 * Attributes are at LEAST as long as the ID & length
671 * fields. Anything shorter is an invalid attribute.
674 librad_log("WARNING: Malformed RADIUS packet from host %s: attribute %d too short",
675 ip_ntoa(host_ipaddr, packet->src_ipaddr),
682 * Sanity check the attributes for length.
685 default: /* don't do anything by default */
689 seen_eap |= PW_EAP_MESSAGE;
692 case PW_MESSAGE_AUTHENTICATOR:
693 if (attr[1] != 2 + AUTH_VECTOR_LEN) {
694 librad_log("WARNING: Malformed RADIUS packet from host %s: Message-Authenticator has invalid length %d",
695 ip_ntoa(host_ipaddr, packet->src_ipaddr),
700 seen_eap |= PW_MESSAGE_AUTHENTICATOR;
705 * FIXME: Look up the base 255 attributes in the
706 * dictionary, and switch over their type. For
707 * integer/date/ip, the attribute length SHOULD
710 count -= attr[1]; /* grab the attribute length */
712 num_attributes++; /* seen one more attribute */
716 * If the attributes add up to a packet, it's allowed.
718 * If not, we complain, and throw the packet away.
721 librad_log("WARNING: Malformed RADIUS packet from host %s: packet attributes do NOT exactly fill the packet",
722 ip_ntoa(host_ipaddr, packet->src_ipaddr));
728 * If we've seen an EAP-Message attribute without a
729 * Message-Authenticator attribute, it's invalid.
731 if (((seen_eap & PW_EAP_MESSAGE) == PW_EAP_MESSAGE) &&
732 ((seen_eap & PW_MESSAGE_AUTHENTICATOR) != PW_MESSAGE_AUTHENTICATOR)) {
733 librad_log("WARNING: Malformed RADIUS packet from host %s: Contains EAP-Message, but no Message-Authenticator",
734 ip_ntoa(host_ipaddr, packet->src_ipaddr));
740 * If we're configured to look for a maximum number of
741 * attributes, and we've seen more than that maximum,
742 * then throw the packet away, as a possible DoS.
744 if ((librad_max_attributes > 0) &&
745 (num_attributes > librad_max_attributes)) {
746 librad_log("WARNING: Possible DoS attack from host %s: Too many attributes in request (received %d, max %d are allowed).",
747 ip_ntoa(host_ipaddr, packet->src_ipaddr),
748 num_attributes, librad_max_attributes);
754 if ((hdr->code > 0) && (hdr->code < 14)) {
755 printf("rad_recv: %s packet from host %s:%d",
756 packet_codes[hdr->code],
757 ip_ntoa(host_ipaddr, packet->src_ipaddr), packet->src_port);
759 printf("rad_recv: Packet from host %s:%d code=%d",
760 ip_ntoa(host_ipaddr, packet->src_ipaddr), packet->src_port,
763 printf(", id=%d, length=%d\n", hdr->id, totallen);
767 * Fill RADIUS header fields
769 packet->code = hdr->code;
770 packet->id = hdr->id;
771 memcpy(packet->vector, hdr->vector, AUTH_VECTOR_LEN);
774 * Now that we've sanity checked the packet, we can allocate
775 * memory for it, and copy the data from the local area to
778 if ((packet->data = malloc(packet->data_len)) == NULL) {
780 librad_log("out of memory");
783 memcpy(packet->data, data, packet->data_len);
789 * Calculate/check digest, and decode radius attributes.
791 int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original, const char *secret)
797 VALUE_PAIR *first_pair;
805 radius_packet_t *hdr;
807 hdr = (radius_packet_t *)packet->data;
810 * Before we allocate memory for the attributes, do more
814 length = packet->data_len - AUTH_HDR_LEN;
816 uint8_t msg_auth_vector[AUTH_VECTOR_LEN];
817 uint8_t calc_auth_vector[AUTH_VECTOR_LEN];
822 default: /* don't do anything. */
826 * Note that more than one Message-Authenticator
827 * attribute is invalid.
829 case PW_MESSAGE_AUTHENTICATOR:
830 memcpy(msg_auth_vector, &ptr[2], sizeof(msg_auth_vector));
831 memset(&ptr[2], 0, AUTH_VECTOR_LEN);
833 switch (packet->code) {
837 case PW_AUTHENTICATION_ACK:
838 case PW_AUTHENTICATION_REJECT:
839 case PW_ACCESS_CHALLENGE:
841 memcpy(packet->data + 4, original->vector, AUTH_VECTOR_LEN);
846 lrad_hmac_md5(packet->data, packet->data_len,
847 secret, strlen(secret), calc_auth_vector);
848 if (memcmp(calc_auth_vector, msg_auth_vector,
849 sizeof(calc_auth_vector)) != 0) {
851 librad_log("Received packet from %s with invalid Message-Authenticator!",
852 ip_ntoa(buffer, packet->src_ipaddr));
854 } /* else the message authenticator was good */
857 * Reinitialize Authenticators.
859 memcpy(&ptr[2], msg_auth_vector, AUTH_VECTOR_LEN);
860 memcpy(packet->data + 4, packet->vector, AUTH_VECTOR_LEN);
862 } /* switch over the attributes */
866 } /* loop over the packet, sanity checking the attributes */
869 * Calculate and/or verify digest.
871 switch(packet->code) {
872 case PW_AUTHENTICATION_REQUEST:
873 case PW_STATUS_SERVER:
875 * The authentication vector is random
876 * nonsense, invented by the client.
880 case PW_ACCOUNTING_REQUEST:
881 if (calc_acctdigest(packet, secret) > 1) {
883 librad_log("Received Accounting-Request packet "
884 "from %s with invalid signature!",
885 ip_ntoa(buffer, packet->src_ipaddr));
890 /* Verify the reply digest */
891 case PW_AUTHENTICATION_ACK:
892 case PW_AUTHENTICATION_REJECT:
893 case PW_ACCOUNTING_RESPONSE:
894 if (calc_replydigest(packet, original, secret) > 1) {
896 librad_log("Received %s packet "
897 "from %s with invalid signature!",
898 packet_codes[packet->code],
899 ip_ntoa(buffer, packet->src_ipaddr));
906 * Extract attribute-value pairs
909 length = packet->data_len - AUTH_HDR_LEN;
918 attribute = *ptr++ | (vendorcode << 16);
929 * This could be a Vendor-Specific attribute.
932 if ((vendorlen <= 0) &&
933 (attribute == PW_VENDOR_SPECIFIC) &&
935 memcpy(&lvalue, ptr, 4);
936 vendorpec = ntohl(lvalue);
937 if ((vendorcode = dict_vendorcode(vendorpec)) != 0) {
939 if (vendorpec == VENDORPEC_USR) {
941 memcpy(&lvalue, ptr, 4);
942 /*printf("received USR %04x\n", ntohl(lvalue));*/
943 attribute = (ntohl(lvalue) & 0xFFFF) |
951 vendorlen = attrlen - 4;
952 attribute = *ptr++ | (vendorcode << 16);
959 * Else the vendor wasn't found...
964 * FIXME: should we us paircreate() ?
966 if ((pair = malloc(sizeof(VALUE_PAIR))) == NULL) {
967 pairfree(&first_pair);
968 librad_log("out of memory");
973 memset(pair, 0, sizeof(VALUE_PAIR));
974 if ((attr = dict_attrbyvalue(attribute)) == NULL) {
975 snprintf(pair->name, sizeof(pair->name), "Attr-%d", attribute);
976 pair->type = PW_TYPE_STRING;
978 strcpy(pair->name, attr->name);
979 pair->type = attr->type;
981 pair->attribute = attribute;
982 pair->length = attrlen;
985 switch (pair->type) {
988 case PW_TYPE_ABINARY:
991 * Hmm... this is based on names right
992 * now. We really shouldn't do this.
993 * It should be based on the value of
994 * the attribute (VSA or not).
996 if ((strcmp(pair->name, "Ascend-Send-Secret") == 0) ||
997 (strcmp(pair->name, "Ascend-Receive-Secret") == 0)) {
998 uint8_t my_digest[AUTH_VECTOR_LEN];
999 make_secret( my_digest, original->vector,
1001 memcpy(pair->strvalue, my_digest, AUTH_VECTOR_LEN );
1002 pair->strvalue[AUTH_VECTOR_LEN] = '\0';
1003 pair->length = strlen(pair->strvalue);
1005 /* attrlen always < MAX_STRING_LEN */
1006 memcpy(pair->strvalue, ptr, attrlen);
1009 case PW_TYPE_INTEGER:
1011 case PW_TYPE_IPADDR:
1013 * Check for RFC compliance. If the
1014 * attribute isn't compliant, turn it
1015 * into a string of raw octets.
1017 * Also set the lvalue to something
1018 * which should never match anything.
1021 pair->type = PW_TYPE_OCTETS;
1022 memcpy(pair->strvalue, ptr, attrlen);
1023 pair->lvalue = 0xbaddbadd;
1026 memcpy(&lvalue, ptr, 4);
1027 if (attr->type != PW_TYPE_IPADDR)
1028 pair->lvalue = ntohl(lvalue);
1030 pair->lvalue = lvalue;
1034 DEBUG(" %s (Unknown Type %d)\n",
1035 attr->name,attr->type);
1043 if (first_pair == NULL)
1052 if (vendorlen > 0) vendorlen -= (attrlen + 2);
1055 packet->vps = first_pair;
1058 * Merge information from the outside world into our
1059 * random vector pool.
1061 for (length = 0; length < AUTH_VECTOR_LEN; length++) {
1062 random_vector_pool[length] ^= packet->vector[length];
1072 * We assume that the passwd buffer passed is big enough.
1073 * RFC2138 says the password is max 128 chars, so the size
1074 * of the passwd buffer must be at least 129 characters.
1075 * Preferably it's just MAX_STRING_LEN.
1077 * int *pwlen is updated to the new length of the encrypted
1078 * password - a multiple of 16 bytes.
1080 #define AUTH_PASS_LEN (16)
1081 int rad_pwencode(char *passwd, int *pwlen, const char *secret, const char *vector)
1083 uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 1];
1084 char digest[AUTH_VECTOR_LEN];
1085 int i, n, secretlen;
1089 * Padd password to multiple of AUTH_PASS_LEN bytes.
1091 len = strlen(passwd);
1092 if (len > 128) len = 128;
1094 if (len % AUTH_PASS_LEN != 0) {
1095 n = AUTH_PASS_LEN - (len % AUTH_PASS_LEN);
1096 for (i = len; n > 0; n--, i++)
1102 * Use the secret to setup the decryption digest
1104 secretlen = strlen(secret);
1105 memcpy(buffer, secret, secretlen);
1106 memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN);
1107 librad_md5_calc((u_char *)digest, buffer, secretlen + AUTH_VECTOR_LEN);
1110 * Now we can encode the password *in place*
1112 for (i = 0; i < AUTH_PASS_LEN; i++)
1113 passwd[i] ^= digest[i];
1115 if (len <= AUTH_PASS_LEN) return 0;
1118 * Length > AUTH_PASS_LEN, so we need to use the extended
1121 for (n = 0; n < 128 && n <= (len - AUTH_PASS_LEN); n += AUTH_PASS_LEN) {
1122 memcpy(buffer + secretlen, passwd + n, AUTH_PASS_LEN);
1123 librad_md5_calc((u_char *)digest, buffer, secretlen + AUTH_PASS_LEN);
1124 for (i = 0; i < AUTH_PASS_LEN; i++)
1125 passwd[i + n + AUTH_PASS_LEN] ^= digest[i];
1134 int rad_pwdecode(char *passwd, int pwlen, const char *secret, const char *vector)
1136 uint8_t buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 1];
1137 char digest[AUTH_VECTOR_LEN];
1138 char r[AUTH_VECTOR_LEN];
1140 int i, n, secretlen;
1144 * Use the secret to setup the decryption digest
1146 secretlen = strlen(secret);
1147 memcpy(buffer, secret, secretlen);
1148 memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN);
1149 librad_md5_calc((u_char *)digest, buffer, secretlen + AUTH_VECTOR_LEN);
1152 * Now we can decode the password *in place*
1154 memcpy(r, passwd, AUTH_PASS_LEN);
1155 for (i = 0; i < AUTH_PASS_LEN && i < pwlen; i++)
1156 passwd[i] ^= digest[i];
1158 if (pwlen <= AUTH_PASS_LEN) {
1159 passwd[pwlen+1] = 0;
1164 * Length > AUTH_PASS_LEN, so we need to use the extended
1167 rlen = ((pwlen - 1) / AUTH_PASS_LEN) * AUTH_PASS_LEN;
1169 for (n = rlen; n > 0; n -= AUTH_PASS_LEN ) {
1170 s = (n == AUTH_PASS_LEN) ? r : (passwd + n - AUTH_PASS_LEN);
1171 memcpy(buffer + secretlen, s, AUTH_PASS_LEN);
1172 librad_md5_calc((u_char *)digest, buffer, secretlen + AUTH_PASS_LEN);
1173 for (i = 0; i < AUTH_PASS_LEN && (i + n) < pwlen; i++)
1174 passwd[i + n] ^= digest[i];
1182 * Encode a CHAP password
1184 * FIXME: might not work with Ascend because
1185 * we use vp->length, and Ascend gear likes
1186 * to send an extra '\0' in the string!
1188 int rad_chap_encode(RADIUS_PACKET *packet, char *output, int id, VALUE_PAIR *password)
1192 char string[MAX_STRING_LEN];
1193 VALUE_PAIR *challenge;
1196 * Sanity check the input parameters
1198 if ((packet == NULL) || (password == NULL)) {
1203 * Note that the password VP can be EITHER
1204 * a Password attribute (from a check-item list),
1205 * or a CHAP-Password attribute (the client asking
1206 * the library to encode it).
1214 memcpy(ptr, password->strvalue, password->length);
1215 ptr += password->length;
1216 i += password->length;
1219 * Use Chap-Challenge pair if present,
1220 * Request-Authenticator otherwise.
1222 challenge = pairfind(packet->vps, PW_CHAP_CHALLENGE);
1224 memcpy(ptr, challenge->strvalue, challenge->length);
1225 i += challenge->length;
1227 memcpy(ptr, packet->vector, AUTH_VECTOR_LEN);
1228 i += AUTH_VECTOR_LEN;
1232 librad_md5_calc((u_char *)output + 1, (u_char *)string, i);
1238 * Create a random vector of AUTH_VECTOR_LEN bytes.
1240 static void random_vector(uint8_t *vector)
1243 static int did_srand = 0;
1244 static int counter = 0;
1246 static int urandom_fd = -1;
1249 * Use /dev/urandom if available.
1251 if (urandom_fd > -2) {
1253 * Open urandom fd if not yet opened.
1256 urandom_fd = open("/dev/urandom", O_RDONLY);
1257 if (urandom_fd < 0) {
1259 * It's not there, don't try
1262 DEBUG("Cannot open /dev/urandom, using rand()\n");
1266 fcntl(urandom_fd, F_SETFD, 1);
1271 if (read(urandom_fd, (char *) vector, AUTH_VECTOR_LEN)
1275 * We didn't get 16 bytes - fall
1276 * back on rand) and don't try again.
1278 DEBUG("Read short packet from /dev/urandom, using rand()\n");
1285 srand(time(NULL) + getpid());
1288 * Now that we have a bad random seed, let's
1289 * make it a little better by MD5'ing it.
1291 for (i = 0; i < (int)sizeof(random_vector_pool); i++) {
1292 random_vector_pool[i] += rand() & 0xff;
1295 librad_md5_calc((u_char *) random_vector_pool,
1296 (u_char *) random_vector_pool,
1297 sizeof(random_vector_pool));
1303 * Modify our random pool, based on the counter,
1304 * and put the resulting information through MD5,
1305 * so it's all mashed together.
1308 random_vector_pool[AUTH_VECTOR_LEN] += (counter & 0xff);
1309 librad_md5_calc((u_char *) random_vector_pool,
1310 (u_char *) random_vector_pool,
1311 sizeof(random_vector_pool));
1314 * And do another MD5 hash of the result, to give
1315 * the user a random vector. This ensures that the
1316 * user has a random vector, without giving them
1317 * an exact image of what's in the random pool.
1319 librad_md5_calc((u_char *) vector,
1320 (u_char *) random_vector_pool,
1321 sizeof(random_vector_pool));
1326 * Allocate a new RADIUS_PACKET
1328 RADIUS_PACKET *rad_alloc(int newvector)
1332 if ((rp = malloc(sizeof(RADIUS_PACKET))) == NULL) {
1333 librad_log("out of memory");
1336 memset(rp, 0, sizeof(RADIUS_PACKET));
1338 random_vector(rp->vector);
1344 * Free a RADIUS_PACKET
1346 void rad_free(RADIUS_PACKET **radius_packet_ptr)
1348 RADIUS_PACKET *radius_packet;
1350 if (!radius_packet_ptr) return;
1351 radius_packet = *radius_packet_ptr;
1353 if (radius_packet->data) free(radius_packet->data);
1354 if (radius_packet->vps) pairfree(&radius_packet->vps);
1356 free(radius_packet);
1358 *radius_packet_ptr = NULL;
1361 /*************************************************************************
1363 * Function: make_secret
1365 * Purpose: Build an encrypted secret value to return in a reply
1366 * packet. The secret is hidden by xoring with a MD5 digest
1367 * created from the shared secret and the authentication
1368 * vector. We put them into MD5 in the reverse order from
1369 * that used when encrypting passwords to RADIUS.
1371 *************************************************************************/
1372 static void make_secret(unsigned char *digest, uint8_t *vector,
1373 const char *secret, char *value)
1375 u_char buffer[256 + AUTH_VECTOR_LEN];
1376 int secretLen = strlen(secret);
1379 memcpy(buffer, vector, AUTH_VECTOR_LEN );
1380 memcpy(buffer + AUTH_VECTOR_LEN, secret, secretLen );
1382 librad_md5_calc(digest, buffer, AUTH_VECTOR_LEN + secretLen );
1383 memset(buffer, 0, sizeof(buffer));
1385 for ( i = 0; i < AUTH_VECTOR_LEN; i++ ) {
1386 digest[i] ^= value[i];