📄 radius.c
字号:
const char *secret){ radius_packet_t *hdr = (radius_packet_t *)packet->data; /* * It wasn't assigned an Id, this is bad! */ if (packet->id < 0) { librad_log("ERROR: RADIUS packets must be assigned an Id."); return -1; } if (!packet->data || (packet->data_len < AUTH_HDR_LEN) || (packet->offset < 0)) { librad_log("ERROR: You must call rad_encode() before rad_sign()"); return -1; } /* * If there's a Message-Authenticator, update it * now, BEFORE updating the authentication vector. */ if (packet->offset > 0) { uint8_t calc_auth_vector[AUTH_VECTOR_LEN]; switch (packet->code) { case PW_ACCOUNTING_REQUEST: case PW_ACCOUNTING_RESPONSE: case PW_DISCONNECT_REQUEST: case PW_DISCONNECT_ACK: case PW_DISCONNECT_NAK: case PW_COA_REQUEST: case PW_COA_ACK: case PW_COA_NAK: memset(hdr->vector, 0, AUTH_VECTOR_LEN); break; case PW_AUTHENTICATION_ACK: case PW_AUTHENTICATION_REJECT: case PW_ACCESS_CHALLENGE: if (!original) { librad_log("ERROR: Cannot sign response packet without a request packet."); return -1; } memcpy(hdr->vector, original->vector, AUTH_VECTOR_LEN); break; default: /* others have vector already set to zero */ break; } /* * Set the authentication vector to zero, * calculate the signature, and put it * into the Message-Authenticator * attribute. */ fr_hmac_md5(packet->data, packet->data_len, (const uint8_t *) secret, strlen(secret), calc_auth_vector); memcpy(packet->data + packet->offset + 2, calc_auth_vector, AUTH_VECTOR_LEN); /* * Copy the original request vector back * to the raw packet. */ memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN); } /* * Switch over the packet code, deciding how to * sign the packet. */ switch (packet->code) { /* * Request packets are not signed, bur * have a random authentication vector. */ case PW_AUTHENTICATION_REQUEST: case PW_STATUS_SERVER: break; /* * Reply packets are signed with the * authentication vector of the request. */ default: { uint8_t digest[16]; FR_MD5_CTX context; fr_MD5Init(&context); fr_MD5Update(&context, packet->data, packet->data_len); fr_MD5Update(&context, (const uint8_t *) secret, strlen(secret)); fr_MD5Final(digest, &context); memcpy(hdr->vector, digest, AUTH_VECTOR_LEN); memcpy(packet->vector, digest, AUTH_VECTOR_LEN); break; } }/* switch over packet codes */ return 0;}/* * Reply to the request. Also attach * reply attribute value pairs and any user message provided. */int rad_send(RADIUS_PACKET *packet, const RADIUS_PACKET *original, const char *secret){ VALUE_PAIR *reply; const char *what; char ip_buffer[128]; /* * Maybe it's a fake packet. Don't send it. */ if (!packet || (packet->sockfd < 0)) { return 0; } if ((packet->code > 0) && (packet->code < MAX_PACKET_CODE)) { what = packet_codes[packet->code]; } else { what = "Reply"; } /* * First time through, allocate room for the packet */ if (!packet->data) { /* * Encode the packet. */ if (rad_encode(packet, original, secret) < 0) { return -1; } /* * Re-sign it, including updating the * Message-Authenticator. */ if (rad_sign(packet, original, secret) < 0) { return -1; } /* * If packet->data points to data, then we print out * the VP list again only for debugging. */ } else if (librad_debug) { DEBUG("Sending %s of id %d to %s port %d\n", what, packet->id, inet_ntop(packet->dst_ipaddr.af, &packet->dst_ipaddr.ipaddr, ip_buffer, sizeof(ip_buffer)), packet->dst_port); for (reply = packet->vps; reply; reply = reply->next) { if ((VENDOR(reply->attribute) == 0) && ((reply->attribute & 0xFFFF) > 0xff)) continue; debug_pair(reply); } } /* * And send it on it's way. */ return rad_sendto(packet->sockfd, packet->data, packet->data_len, 0, &packet->src_ipaddr, packet->src_port, &packet->dst_ipaddr, packet->dst_port);}/* * Validates the requesting client NAS. Calculates the * signature based on the clients private key. */static int calc_acctdigest(RADIUS_PACKET *packet, const char *secret){ uint8_t digest[AUTH_VECTOR_LEN]; FR_MD5_CTX context; /* * Zero out the auth_vector in the received packet. * Then append the shared secret to the received packet, * and calculate the MD5 sum. This must be the same * as the original MD5 sum (packet->vector). */ memset(packet->data + 4, 0, AUTH_VECTOR_LEN); /* * MD5(packet + secret); */ fr_MD5Init(&context); fr_MD5Update(&context, packet->data, packet->data_len); fr_MD5Update(&context, (const uint8_t *) secret, strlen(secret)); fr_MD5Final(digest, &context); /* * Return 0 if OK, 2 if not OK. */ if (memcmp(digest, packet->vector, AUTH_VECTOR_LEN) != 0) return 2; return 0;}/* * Validates the requesting client NAS. Calculates the * signature based on the clients private key. */static int calc_replydigest(RADIUS_PACKET *packet, RADIUS_PACKET *original, const char *secret){ uint8_t calc_digest[AUTH_VECTOR_LEN]; FR_MD5_CTX context; /* * Very bad! */ if (original == NULL) { return 3; } /* * Copy the original vector in place. */ memcpy(packet->data + 4, original->vector, AUTH_VECTOR_LEN); /* * MD5(packet + secret); */ fr_MD5Init(&context); fr_MD5Update(&context, packet->data, packet->data_len); fr_MD5Update(&context, (const uint8_t *) secret, strlen(secret)); fr_MD5Final(calc_digest, &context); /* * Copy the packet's vector back to the packet. */ memcpy(packet->data + 4, packet->vector, AUTH_VECTOR_LEN); /* * Return 0 if OK, 2 if not OK. */ if (memcmp(packet->vector, calc_digest, AUTH_VECTOR_LEN) != 0) return 2; return 0;}/* * See if the data pointed to by PTR is a valid RADIUS packet. * * packet is not 'const * const' because we may update data_len, * if there's more data in the UDP packet than in the RADIUS packet. */int rad_packet_ok(RADIUS_PACKET *packet, int flags){ uint8_t *attr; int totallen; int count; radius_packet_t *hdr; char host_ipaddr[128]; int require_ma = 0; int seen_ma = 0; int num_attributes; /* * Check for packets smaller than the packet header. * * RFC 2865, Section 3., subsection 'length' says: * * "The minimum length is 20 ..." */ if (packet->data_len < AUTH_HDR_LEN) { librad_log("WARNING: Malformed RADIUS packet from host %s: too short (received %d < minimum %d)", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, host_ipaddr, sizeof(host_ipaddr)), packet->data_len, AUTH_HDR_LEN); return 0; } /* * RFC 2865, Section 3., subsection 'length' says: * * " ... and maximum length is 4096." */ if (packet->data_len > MAX_PACKET_LEN) { librad_log("WARNING: Malformed RADIUS packet from host %s: too long (received %d > maximum %d)", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, host_ipaddr, sizeof(host_ipaddr)), packet->data_len, MAX_PACKET_LEN); return 0; } /* * Check for packets with mismatched size. * i.e. We've received 128 bytes, and the packet header * says it's 256 bytes long. */ totallen = (packet->data[2] << 8) | packet->data[3]; hdr = (radius_packet_t *)packet->data; /* * Code of 0 is not understood. * Code of 16 or greate is not understood. */ if ((hdr->code == 0) || (hdr->code >= MAX_PACKET_CODE)) { librad_log("WARNING: Bad RADIUS packet from host %s: unknown packet code%d ", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, host_ipaddr, sizeof(host_ipaddr)), hdr->code); return 0; } /* * Message-Authenticator is required in Status-Server * packets, otherwise they can be trivially forged. */ if (hdr->code == PW_STATUS_SERVER) require_ma = 1; /* * It's also required if the caller asks for it. */ if (flags) require_ma = 1; /* * Repeat the length checks. This time, instead of * looking at the data we received, look at the value * of the 'length' field inside of the packet. * * Check for packets smaller than the packet header. * * RFC 2865, Section 3., subsection 'length' says: * * "The minimum length is 20 ..." */ if (totallen < AUTH_HDR_LEN) { librad_log("WARNING: Malformed RADIUS packet from host %s: too short (length %d < minimum %d)", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, host_ipaddr, sizeof(host_ipaddr)), totallen, AUTH_HDR_LEN); return 0; } /* * And again, for the value of the 'length' field. * * RFC 2865, Section 3., subsection 'length' says: * * " ... and maximum length is 4096." */ if (totallen > MAX_PACKET_LEN) { librad_log("WARNING: Malformed RADIUS packet from host %s: too long (length %d > maximum %d)", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, host_ipaddr, sizeof(host_ipaddr)), totallen, MAX_PACKET_LEN); return 0; } /* * RFC 2865, Section 3., subsection 'length' says: * * "If the packet is shorter than the Length field * indicates, it MUST be silently discarded." * * i.e. No response to the NAS. */ if (packet->data_len < totallen) { librad_log("WARNING: Malformed RADIUS packet from host %s: received %d octets, packet length says %d", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, host_ipaddr, sizeof(host_ipaddr)), packet->data_len, totallen); return 0; } /* * RFC 2865, Section 3., subsection 'length' says: * * "Octets outside the range of the Length field MUST be * treated as padding and ignored on reception." */ if (packet->data_len > totallen) { /* * We're shortening the packet below, but just * to be paranoid, zero out the extra data. */ memset(packet->data + totallen, 0, packet->data_len - totallen); packet->data_len = totallen; } /* * Walk through the packet's attributes, ensuring that * they add up EXACTLY to the size of the packet. * * If they don't, then the attributes either under-fill * or over-fill the packet. Any parsing of the packet * is impossible, and will result in unknown side effects. * * This would ONLY happen with buggy RADIUS implementations, * or with an intentional attack. Either way, we do NOT want * to be vulnerable to this problem. */ attr = hdr->data; count = totallen - AUTH_HDR_LEN; num_attributes = 0; while (count > 0) { /* * Attribute number zero is NOT defined. */ if (attr[0] == 0) { librad_log("WARNING: Malformed RADIUS packet from host %s: Invalid attribute 0", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, host_ipaddr, sizeof(host_ipaddr))); return 0; } /* * Attributes are at LEAST as long as the ID & length * fields. Anything shorter is an invalid attribute. */ if (attr[1] < 2) { librad_log("WARNING: Malformed RADIUS packet from host %s: attribute %d too short", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, host_ipaddr, sizeof(host_ipaddr)), attr[0]); return 0; } /* * Sanity check the attributes for length. */ switch (attr[0]) { default: /* don't do anything by default */ break; /* * If there's an EAP-Message, we require * a Message-Authenticator. */ case PW_EAP_MESSAGE: require_ma = 1; break; case PW_MESSAGE_AUTHENTICATOR: if (attr[1] != 2 + AUTH_VECTOR_LEN) { librad_log("WARNING: Malformed RADIUS packet from host %s: Message-Authenticator has invalid length %d", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, host_ipaddr, sizeof(host_ipaddr)), attr[1] - 2); return 0; } seen_ma = 1; break; } /* * FIXME: Look up the base 255 attributes in the * dictionary, and switch over their type. For * integer/date/ip, the attribute length SHOULD * be 6. */ count -= attr[1]; /* grab the attribute length */ attr += attr[1]; num_attributes++; /* seen one more attribute */ } /* * If the attributes add up to a packet, it's allowed. * * If not, we complain, and throw the packet away. */ if (count != 0) { librad_log("WARNING: Malformed RADIUS packet from host %s: packet attributes do NOT exactly fill the packet", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, host_ipaddr, sizeof(host_ipaddr))); return 0; } /* * If we're configured to look for a maximum number of * attributes, and we've seen more than that maximum, * then throw the packet away, as a possible DoS. */ if ((librad_max_attributes > 0) && (num_attributes > librad_max_attributes)) { 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 0; } /* * http://www.freeradius.org/rfc/rfc2869.html#EAP-Message * * A packet with an EAP-Message attribute MUST also have * a Message-Authenticator attribute. * * A Message-Authenticator all by itself is OK, though. * * Similarly, Status-Server packets MUST contain * Message-Authenticator attributes. */ if (require_ma && ! seen_ma) { librad_log("WARNING: Insecure packet from host %s: Packet does not contain required Message-Authenticator attribute", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, host_ipaddr, sizeof(host_ipaddr))); return 0; } /* * Fill RADIUS header fields */ packet->code = hdr->code; packet->id = hdr->id; memcpy(packet->vector, hdr->vector, AUTH_VECTOR_LEN); return 1;}/* * Receive UDP client requests, and fill in * the basics of a RADIUS_PACKET structure. */RADIUS_PACKET *rad_recv(int fd, int flags){ RADIUS_PACKET *packet; /* * Allocate the new request data structure */ if ((packet = malloc(sizeof(*packet))) == NULL) { librad_log("out of memory"); return NULL; } memset(packet, 0, sizeof(*packet)); packet->data_len = rad_recvfrom(fd, &packet->data, 0, &packet->src_ipaddr, &packet->src_port, &packet->dst_ipaddr, &packet->dst_port);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -